2014-10-06 15 views
8

Di seguito è riportato un programma che utilizza pthreads.Output imprevisto in un programma con multithreading

#include <pthread.h> // posix threads 
#include <stdio.h> 
#include <stdlib.h> 

/* to compile use -lpthread */ 

void * sample_thread(void *); 

#define MAX 10 

int main() 
{ 
    pthread_t tid; 
    pthread_attr_t attr; 
    int k; 

    pthread_attr_init(&attr); // set default attributes 
    pthread_create(&tid, &attr, sample_thread, NULL); // create new thread 
    // sample_thread will run as the new thread 

    for(k=0; k<MAX; k++) { 
    printf("Hi I'am %s %d \n",__func__,k); 
    } 


    //this would kill all the threads, 
} 

void * sample_thread(void * p) 
{ 
    int k; 
    for(k=0; k<MAX; k++) { 
    printf("Hi I'am %s %d \n",__func__,k); 
    } 

} 

Ogni volta quando si esegue il programma mi aspetto di ottenere il numero diverso di numeri di esecuzione dal thread principale e il thread figlio (perché la principale uscita filo forza prima che il bambino). A volte sto ottenendo questo risultato atteso. Ma ho ottenuto un risultato come segue, che non riesco a capire perché.

Hi I'am main 0 
Hi I'am main 1 
Hi I'am main 2 
Hi I'am main 3 
Hi I'am main 4 
Hi I'am main 5 
Hi I'am main 6 
Hi I'am main 7 
Hi I'am main 8 
Hi I'am main 9 
Hi I'am sample_thread 0 
Hi I'am sample_thread 0 
Hi I'am sample_thread 1 
Hi I'am sample_thread 2 
Hi I'am sample_thread 3 
Hi I'am sample_thread 4 
Hi I'am sample_thread 4 
Hi I'am sample_thread 5 

Perché il filo di prova 0 e 4 sono stati stampati due volte?

+1

Puoi dirci quale sistema operativo stai utilizzando? Non sembra che ci sia qualcosa di sbagliato nel tuo programma e ho il sospetto che potrebbe essere un bug nell'implementazione ('exit 'è richiesto da POSIX per sincronizzarsi con le operazioni stdio, ma se non lo fa, potrebbero esserci razze di dati (e la corruzione casuale) quando scarica lo 'stdout' simultaneamente con un altro thread che scrive su' stdout'). –

+0

È Ubuntu 13.10 – DesirePRG

risposta

8

Come evidenziato da @R .. nei commenti, questo sembra essere a bug nell'implementazione di glibc (presupponendo che si utilizzi Linux - Posso riprodurlo su Linux 2.17 compilato con GCC 4.9.1), in exit() non garantisce, durante lo streaming e la chiusura dei flussi, non c'è razza quando viene chiamata da un thread quando più thread usano lo stdout.

Il seguente da flockfile manuale indica chiaramente che il comportamento osservato non è corretto:

Le funzioni stdio sono thread-safe. Ciò è ottenuto da assegnando a ciascun oggetto FILE un conto di blocco e (se il conto di blocco è diverso da zero) un thread proprietario. Per ogni chiamata di libreria, queste funzioni attendono finché l'oggetto FILE non è più bloccato da un diverso thread , quindi lo bloccano, eseguono l'I/O richiesto e sbloccano nuovamente l'oggetto .

Alla luce di ciò, le seguenti opzioni possono essere considerate una soluzione alternativa (in quanto non vi è alcuna risposta alla segnalazione di bug) a questo caso particolare che abbiamo osservato qui.


Sia il thread "condividere" il flusso stdout e credo, l'uscita "extra" viene stampato per l'uscita prematura di thread principale.

printf buffer (in sample_thread()) l'output e prima che potesse cancellare il suo buffer (a causa di \n in printfs), il thread principale termina. Quindi forzare lo svuotamento del buffer stdout quando il processo termina.

Per risolvere,

1) si potrebbe chiamare setbuf() in main() prima di creare il filo:

setbuf(stdout, NULL); 

al non tampone stdout a tutti.

Oppure
2) chiamare pthread_exit() in entrambi i thread in modo che il processo continui se uno dei fili muore.

Oppure
3) chiamare pthread_join() in filo principale cosicché thread principale attende il completamento sample_thread thread.

Uno di questi eviterà il problema.

+0

sulla prima opzione. dove esattamente dovrei chiamare la funzione setbuf? – DesirePRG

+1

sulla seconda opzione non chiama pthread_exit solo nella funzione principale abbastanza? – DesirePRG

+1

1. Inserire 'setbuf()' prima del primo utilizzo del buffer da impostare. Qui: 'stdout' usa implicitamente da' printf() '. 2. Chiamare 'pthread_exit()' in 'main()' è sufficiente. – alk

Problemi correlati