2010-02-02 12 views

risposta

3

Questa era una buona domanda, anche se domande simili sono state poste qui molte volte. Ero interessato all'aspetto OSX perché cercavo di mettermi al corrente su quel sistema da solo. (forse dovresti aggiungere il tag OSX)

I THINK fprintf() è thread-safe su OSX. La mia prima ragione è che il popolo di Darwin andava in quella direzione, come dimostra la sua scelta di abbandonare l'errno globale della vecchia scuola a favore della funzione errno(). Per la documentazione, basta seguire "/usr/include/errno.h". Senza quello, nessuna delle cose di libc sarebbe thread-safe. Tuttavia l'uso della funzione errno() non prova nulla su fprintf(). È solo l'inizio. Sono sicuro che tutti conoscono almeno una situazione in cui Apple non ha portato avanti con una buona idea.

Un altro motivo per cui credo nella 'thread-safety' di fprintf() è lo source code, che dovrebbe essere "la cosa reale", almeno fino al 10.6 quando Apple ha chiuso (parte/tutto) di OSX. Esegui la scansione di quel codice per "MT-Safe" e vedrai un CLAIM che la versione non locale di "vfprintf()" è sicura da thread. Di nuovo, questo non prova nulla. Eppure è una forma di documentazione, che volevi.

La mia ultima ragione per credere che fprintf() sia thread-safe è stato un caso di test. Questo non prova molto neanche di niente. Forse dimostra che lo spazio del buffer è thread-safe. OK, era una scusa per scrivere un piccolo programma per divertimento. In realtà, non l'ho scritto. Ho trovato uno scheletro online e l'ho modificato. La definizione "FLUSH_BUFFER" ti consente di vedere più chiaramente cosa sta succedendo. Se quella macro non è definita, si ottiene il test del buffer 'sort-of' (stesso testo senza alcuni terminatori di riga). Non riuscivo a capire un modo per organizzare una collisione più significativa dei fili.

Immagino che potresti scrivere su più file. Scrivere su un singolo file è probabilmente un test migliore. Il programma allegato non è un test definitivo. Sebbene possa essere esteso, non sono sicuro che qualsiasi programma possa essere davvero definitivo. Bottom line: forse dovresti semplicemente MUTEX le tue chiamate a 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

Il POSIX thread specifica (alias Pthread), che OS X conforme a, richiede che le funzioni stdio sono sicuri thread. Fornisce inoltre le funzioni flockfile e funlockfile per garantire che altri thread non possano intercalare I/O su un FILE * mentre è bloccato.

Vedere http://pubs.opengroup.org/onlinepubs/007908799/xsh/threads.html, in particolare nella sezione "Filo-sicurezza".