2010-09-11 16 views
23

Il seguente programma mostra che possiamo usare return() o pthread_exit() per restituire una variabile void * disponibile per la variabile di stato pthread_join().return() rispetto a pthread_exit() nelle funzioni start pthread

(1) È preferibile utilizzare l'uno sull'altro?

(2) Perché utilizzare return() funziona? Normalmente pensiamo di ritornare mettendo un valore nello stack ma dal momento che il thread è completato, lo stack dovrebbe svanire. O lo stack non viene distrutto fino a dopo pthread_join()?

(3) Nel tuo lavoro, vedi molto uso della variabile di stato? Sembra che il 90% del codice veda solo i NULL del parametro di stato. Dal momento che qualsiasi cosa è cambiata tramite il vuoto * ptr si riflette già nel thread chiamante, non sembra che sia necessario rinviarlo. Qualsiasi nuovo void * ptr restituito dovrebbe puntare a qualcosa di malloc-ed dal thread iniziale, che lascia al thread ricevente la responsabilità di eliminarlo. Ho sbagliato a pensare che la variabile di stato sia semi-inutile?

#include <iostream> 
#include <pthread.h> 

using namespace std; 

struct taskdata 
{ 
     int x; 
    float y; 
    string z; 
}; 


void* task1(void *data) 
{ 
    taskdata *t = (taskdata *) data; 

    t->x += 25; 
    t->y -= 4.5; 
    t->z = "Goodbye"; 

    return(data); 
} 

void* task2(void *data) 
{ 
    taskdata *t = (taskdata *) data; 

    t->x -= 25; 
    t->y += 4.5; 
    t->z = "World"; 

    pthread_exit(data); 
} 


int main(int argc, char *argv[]) 
{ 
    pthread_t threadID; 

    taskdata t = {10, 10.0, "Hello"}; 

    void *status; 

    cout << "before " << t.x << " " << t.y << " " << t.z << endl; 

    //by return() 

    pthread_create(&threadID, NULL, task1, (void *) &t); 

    pthread_join(threadID, &status); 

    taskdata *ts = (taskdata *) status; 

    cout << "after task1 " << ts->x << " " << ts->y << " " << ts->z << endl; 

    //by pthread_exit() 

    pthread_create(&threadID, NULL, task2, (void *) &t); 

    pthread_join(threadID, &status); 

    ts = (taskdata *) status; 

    cout << "after task2 " << ts->x << " " << ts->y << " " << ts->z << endl; 

} 

Con uscita:

before 10 10 Hello 
after task1 35 5.5 Goodbye 
after task2 10 10 World 

risposta

30

(1) Nel codice C++, utilizzando return provoca la pila per essere variabili svolto e locali distrutti, mentre pthread_exit è garantita solo invocare movimentatori cancellazione registrati pthread_cancel_push() . Su alcuni sistemi questo meccanismo causerà anche il richiamo dei distruttori per le variabili locali C++, ma questo non è garantito per il codice portatile --- controlla la documentazione della piattaforma.

Inoltre main(), return sarà implicitamente chiamare exit(), e quindi terminare il programma, mentre pthread_exit() sarà semplicemente terminare il filo, e il programma rimarrà esecuzione finché tutti i thread terminati o qualche filo chiamate exit(), abort() o un'altra funzione che termina il programma.

(2) L'utilizzo di return funziona in base alle specifiche POSIX. Il valore restituito viene archiviato in un punto in cui è possibile recuperarlo da pthread_join(). Le risorse utilizzate dal thread non vengono recuperate finché non viene chiamato pthread_join().

(3) Non uso mai il valore di ritorno di un thread in thread POSIX grezzi. Tuttavia, tendo a utilizzare strutture di livello superiore come la libreria di thread Boost e, più recentemente, la libreria di thread 0x C++, che fornisce mezzi alternativi per il trasferimento di valori tra thread come i future, che evitano i problemi associati alla gestione della memoria riferirsi a.

+1

Riguardo a (1), pthread_exit non termina immediatamente il thread, esegue prima i gestori di annullamento. Almeno NPTL/g ++ usa lo stesso meccanismo per i gestori di cancellazione e gli agenti di comando C++, quindi pthread_exit in effetti risolve lo stack in quel caso. Allo stesso modo, OpenVMS pthread_exit/thread cancellation disattiva lo stack ed esegue i ddt C++. Probabilmente dovresti controllare il manuale per la tua specifica implementazione di pthread per quanto riguarda il comportamento di pthread_exit e lo stack unwinding. –

+0

Ho chiarito (1) per tenere in considerazione il tuo commento. –

+0

Sto definitivamente comprando il tuo libro :) (spero che venga fuori presto). – celavek

6

Penso che sia preferibile lo return da start_routine, perché garantisce che lo stack di chiamate sia svolto correttamente.

Questo è ancora più importante per C che C++ poiché non ha la magia del distruttore che pulisce il disordine dopo le uscite preliminari. Quindi il tuo codice dovrebbe passare attraverso tutte le parti finali delle routine sullo stack di chiamate per fare free s e allo stesso modo.

Per il motivo per cui questo funziona, questo è semplice

Se i rendimenti start_routine, l'effetto sarà come se ci fosse un implicita chiamata a pthread_exit() utilizzando il valore di ritorno di start_routine come stato di uscita

Per la mia esperienza personale tendo a non utilizzare molto lo stato dei thread terminati. Questo è il motivo per cui spesso i thread sono iniziati detached. Ma questo dovrebbe dipendere molto dall'applicazione e non è certamente generalizzabile.

Problemi correlati