2016-05-26 15 views
2

Ich benutze Strukturen in C++, und ich versuche, Zeiger in diesen Strukturen zu speichern, aber wenn ich versuche, diese Struktur in einem Thread zu verwenden, kann ich die Daten der Struktur nicht erhalten.Pthreads und Strukturen C++

struct threadData { 
    void* memPointer; 
    void* instructionPointer; 
    void* stackPointer; 
    int memsize; 
}; 

void *worker_thread(void *arg) { 
    struct threadData *my_data; 
    my_data = (struct threadData *) arg; 
    cout<<"INSTRUCTION POINTER: "<<my_data->instructionPointer<<endl; 
    cout<<"MEMORY POINTER: "<<my_data->memPointer<<endl; 
    cout<<"STACK POINTER: "<<my_data->stackPointer<<endl; 
    cout<<"MEMORY SIZE: "<<my_data->memsize<<endl; 

} 

int main() { 
    pthread_t my_thread; 
    int ret; 
    struct threadData td = { calloc(1, 32), calloc(1000000, 64),  calloc(34, 4),6475 }; 
    ret = pthread_create(&my_thread, NULL, worker_thread, (void *) &td); 
    pthread_detach(my_thread); 
    //pthread_exit(NULL); 
} 

Aber wenn ich pthread_exit (NULL) nach pthread_detach verwenden kann ich die Informationen der Struktur in der Methode „worker_thread“ verwenden.

+1

Wenn Sie C++ verwenden, warum verwenden Sie nicht einen Konstruktor, um Ihre Struktur zu initialisieren? Sie verwenden auch C-artige Umwandlungen und verwenden das Schlüsselwort 'struct', um auf Ihren Strukturtyp zu verweisen (was in C++ fast nie erforderlich ist). Das ist sehr C-wie C++ - Code ... – DaoWen

+0

C++ 11 Implementierung von dem, was Sie versuchen zu tun: http://coliru.stacked-crooked.com/a/f0b3dadb23bd7bba – kfsone

+1

@ kfsone Sie können Calloc Aufrufe noch ersetzen mit 'new char [x * y]' um es komplett C++ - like zu bekommen. Nur zur Vollständigkeit würde ich die zugewiesenen Daten freigeben/löschen. Sicher, es ist nicht notwendig hier, aber konsequenterweise vor dem Zerstören von zugewiesenem Speicher von vornherein zu denken könnte verhindern, dass Sie in Zukunft Speicherlecks erzeugen ... – Aconcagua

Antwort

2

Ohne pthread_exit kehren Sie von main zurück, und die lokale Variable td wird zerstört, bevor die anderen Threads abgeschlossen sind.

Wenn Sie pthread_exit aufrufen, erzwingen Sie, dass der Haupt-Thread auf den Abschluss der anderen Threads wartet, sodass td nicht zu früh zerstört wird.

Wie @Aconcagua bemerkt, die Dokumentation für pthread_exit besagt, dass der aufrufende Thread beendet wird. Es macht keine Ausnahme für den Haupt-Thread, also zumindest im Prinzip könnte der Stack des Haupt-Threads verschwinden, während die anderen Threads noch ausgeführt wurden. Dies bedeutet, dass Sie selbst beim Aufruf von pthread_exit ein undefiniertes Verhalten haben.

+0

Von [pthread_exit man pages] (http://man7.org/linux/man-pages/man3/pthread_exit.3.html): "Der Wert, auf den retval verweist, sollte sich nicht im Stack des aufrufenden Threads befinden, da der Der Inhalt dieses Stapels ist nicht definiert, nachdem der Thread beendet wurde. " Wenn dies auch für den Hauptthread gilt, gilt das Gleiche für td - und Sie führen zu undefiniertem Verhalten beim Zugriff auf td innerhalb des anderen Threads. – Aconcagua

+0

@Aconcagua: Ich bin mir nicht sicher, welchen Punkt Sie versuchen zu machen, da 'retval' (das Argument für pthread_exit) in diesem Fall NULL wäre. –

+1

Wichtiger Punkt ist nicht retval, aber der Stack wird undefiniert - und in unserem Fall 'td'. Wenn man von dem anderen Thread auf "td" zugreift, ist dies ein nicht definiertes Verhalten (es sei denn, pthread_exit verhält sich anders, wenn es vom Hauptthread aufgerufen wird - es gibt jedoch keine Hinweise in dem von mir bereitgestellten Link). – Aconcagua

3

Da td auf dem Stapel in main zugeordnet ist, wird es durch einige Clean-up-Code, die die Laufzeit ausgeführt wird, nachdem Sie von main zurück. Ordnen Sie Ihre td Struktur auf dem Heap statt auf dem Stapel, und es wird funktionieren wie erwartet:

struct threadData tdVal = { calloc(1, 32), calloc(1000000, 64),  calloc(34, 4),6475 }; 
struct threadData *td = malloc(sizeof(*td)); 
*td = tdVal; 
// ... 
ret = pthread_create(&my_thread, NULL, worker_thread, (void *) td); 

Sie jedoch nach wie vor ein Problem. Returning from main will kill the other pthreads in your program. Da es in Ihrem Code keine Synchronisierung gibt, die verhindert, dass main abgeschlossen wird, bevor worker_thread ausgeführt wird, können Sie nicht einmal garantieren, dass worker_thread überhaupt ausgeführt wird.

sollten Sie wahrscheinlich nicht nehmen Sie den Worker-Thread, und stattdessen pthread_join verwenden, um sicherzustellen es vor der Rückkehr aus main abgeschlossen hat. Beachten Sie auch, dass, wenn Sie sicherstellen, main nicht zurückgibt, bevor worker_thread abgeschlossen ist, dann gibt es kein Problem mit td auf dem Stapel verlassen.

+0

Wenn Sie pthread_join verwenden, haben Sie kein Problem mit td auf dem Stapel. – Aconcagua

+0

@Aconcagua - Ja, danke. Ich habe die Antwort aktualisiert, um diesen Punkt klarzustellen. – DaoWen