2010-02-02 3 views

ответ

3

Это был хороший вопрос, хотя подобные вопросы задавались здесь много раз. Меня интересовал OSX-аспект, потому что я сам пытался встать на скорость в этой системе. (возможно, вы должны добавить тег OSX)

I THINK fprintf() является потокобезопасным на OSX. Моя первая причина в том, что люди Дарвина шли в этом направлении, о чем свидетельствует их выбор, чтобы отказаться от глобальной «errno» старой школы в пользу функции errno(). Для документации просто следуйте «/usr/include/errno.h». Без этого ни один из материалов libc не будет потокобезопасным. Однако использование функции errno() ничего не доказывает в fprintf(). Это просто начало. Я уверен, что каждый знает, по крайней мере, одну ситуацию, в которой Apple не справилась с хорошей идеей.

Еще одна причина, по которой я верю в «безопасность потоков» fprintf(), - это source code, которая должна быть «реальной», по крайней мере до 10,6, когда Apple закрыла (часть/все) OSX. Сканируйте этот код для «MT-Safe», и вы увидите сообщение CLAIM о том, что версия, не относящаяся к языку 'vfprintf(), является потокобезопасной. Опять же, это ничего не доказывает. Но это форма документации, которую вы хотели.

Моя последняя причина полагать, что fprintf() является поточно-безопасным, является тестовым примером. Это тоже ничего не доказывает. Возможно, это доказывает, что буферное пространство является потокобезопасным. Хорошо, это было повод написать небольшую программу для удовольствия. На самом деле, я этого не писал. Я нашел скелет онлайн и изменил его. Определение «FLUSH_BUFFER» позволяет вам более четко видеть, что происходит. Если этот макрос не определен, вы получаете «sort-of» buffer test (тот же текст без каких-либо линейных терминаторов). Я не мог понять, как организовать более значимое столкновение потоков.

Я думаю, вы можете написать несколько файлов. Запись в один файл, вероятно, является лучшим тестом. Прилагаемая программа не является окончательным тестом. Хотя это может быть расширено, я не уверен, что любая программа действительно может быть окончательной. Итог: возможно, вы должны просто MUTEX ваши вызовы 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); 
} 
5

POSIX нитей спецификация (AKA Pthreads), который OS X соответствует, требует, чтобы STDIO функции поточно. Он также предоставляет функции flockfile и funlockfile, чтобы гарантировать, что другие потоки не могут перемежать I/O на FILE *, пока он заблокирован.

См. http://pubs.opengroup.org/onlinepubs/007908799/xsh/threads.html, в частности под рубрикой «Защита резьбы».