在OS X上,fprintf是否线程安全?

7

在OS X上,fprintf是否是线程安全的?如果是,这个文档在哪里可以找到?

2个回答

5

POSIX线程规范(也称为Pthreads),它符合OS X的要求,要求stdio函数是线程安全的。此外,它还提供了flockfilefunlockfile函数,以确保其他线程在FILE *被锁定时无法交错进行I/O。

请参见http://pubs.opengroup.org/onlinepubs/007908799/xsh/threads.html,特别是在标题为“Thread-safety”的部分下。


3
这是一个好问题,尽管类似的问题在这里已经被问了很多次。我对OSX方面很感兴趣,因为我自己也在努力了解那个系统。(也许你应该添加OSX标签)
我认为fprintf()在OSX上是线程安全的。我的第一个理由是,Darwin的人们正在朝这个方向发展,这可以从他们选择放弃老派全局变量'errno'而选择函数errno()来证明。关于文档,请参考'/usr/include/errno.h'。没有这个,所有的libc东西都不会是线程安全的。然而,errno()函数的使用并不能证明fprintf()是否线程安全。这只是一个开始。我相信每个人都知道至少有一种情况,苹果没有实现一个好主意。
我相信fprintf()是“线程安全”的另一个原因是源代码,它被认为是“真正的东西”,至少在10.6之前苹果关闭(部分/全部)OSX。扫描该代码中的“MT-Safe”,你会看到一个声明,即非本地化版本的'vfprintf()'是线程安全的。再次强调,这并不能证明什么。但这是一种文档形式,你想要的。
我相信fprintf()是线程安全的最后一个原因是一个测试用例。这也不能证明什么。也许它证明了缓冲区空间是线程安全的。好吧,这是一个写小程序的借口。实际上,我没有写它。我在线上找到了一个骨架,并进行了修改。“FLUSH_BUFFER”定义允许你更清楚地看到发生了什么。如果未定义该宏,则会得到“类似于”缓冲区测试(没有某些行终止符的相同文本)。我无法想出一种方法来安排更有意义的线程碰撞。
我猜你可能会写入多个文件。写入单个文件可能是更好的测试。附加的程序不是一个明确的测试。虽然它可以扩展,但我不确定任何程序是否真正具有明确性。底线:也许你应该只对fprintf()的调用进行互斥处理。
// artificial test for thread safety of fprintf()
// define FLUSH_BUFFER to get a good picture of what's happening, un-def for a buffer test
// the 'pretty print' (FLUSH_BUFFER) output relies on a mono-spaced font
// a writeable file name on the command line will send output to that file
//

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define FLUSH_BUFFER

#define NTHREAD     5
#define ITERATIONS  3

const char DOTS[] = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . ";
FILE *outFile;

void *PrintHello(void *threadid) {
    long tid;

    tid = (long)threadid;
    for (int i=1; i<=ITERATIONS; i++) {
        long delay = (NTHREAD-tid) * 100000 + (ITERATIONS-i+1) * 10000;
#ifdef FLUSH_BUFFER
        fprintf(outFile, "%*sStart thread  %d iteration %d\n", (tid+1)*4, " ", tid, i);
        usleep(delay);
        fprintf(outFile, "%*sFinish thread %d iteration %d %*.*sw/delay %d\n", 
               (tid+1)*4, " ", tid, i, (NTHREAD-tid+1)*4, (NTHREAD-tid+1)*4, DOTS, delay);
#else
        fprintf(outFile, "Start thread  %d iteration %d   ", tid, i);
        usleep(delay);
        fprintf(outFile, "Finish thread %d iteration %d w/delay %d\n", tid, i, delay);
#endif
    }
    pthread_exit(NULL);
}

int main (int argc, char *argv[]) {
    pthread_t threads[NTHREAD];
    char errStr[100];
    int rc;
    long t;

    if(argc > 1) {
        if(! (outFile = fopen(argv[1], "w"))) {
            perror(argv[1]);
            exit(1);
       }
    } else 
        outFile = stdout;

    for(t=0; t<NTHREAD; t++) {
        fprintf(outFile, "In main: creating thread %ld\n", t);
        if(rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t)) {
            sprintf(errStr, "ERROR; pthread_create() returned %d", rc);
            perror(errStr);
            exit(2);
        }
    }
    pthread_exit(NULL);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接