2016-04-24 11 views
0

Hallo Ich versuche, abgetrennte Threads mit Bedingungsvariablen zu synchronisieren, aber ich fand einen Fehler, der manchmal Speicherverlust verursacht (abhängig von Scheduler-Stimmung). Ich denke, der Code ist selbsterklärend. Ich würde mich über jeden Hinweis freuen.POSIX-Threads - DETACHED-Threads mit Bedingungsvariablen synchronisieren MEMORY LEAK

#include <cstdio> 
#include <cstdlib> 
#include <cstring> 
#include <unistd.h> 
#include <pthread.h> 

using namespace std; 

struct TThrArg 
{ 
    pthread_t m_ID; 
    bool  m_IsRunning; 
}; 

TThrArg   g_Threads[64]; 
int    g_Counter; 
pthread_mutex_t g_Mtx; 
pthread_cond_t g_Cond; 

void * thrFunc (void * arg) 
{ 
    TThrArg * data = (TThrArg *) arg; 

    // do some stuff 
    // ----------------------------------- 
    // for (int i = 0; i < 5000; ++i) 
    // for (int j = 0; j < 5000; ++j) 
    //  int x = 0; 
    // printf("Thread: %lu running...\n", data->m_ID); 
    // ----------------------------------- 

    pthread_mutex_lock(&g_Mtx); 
    memset(data, 0, sizeof(TThrArg)); 
    --g_Counter; 
    pthread_cond_signal(&g_Cond); 
    pthread_mutex_unlock(&g_Mtx); 
    sleep(1); // --> this spot causes that main may end before return NULL so resources will not be freed 
    return NULL; 
} 

void createThread (void) 
{ 
    pthread_mutex_lock(&g_Mtx); 
    for (int i = 0; i < 64; ++i) 
    { 
     if (g_Threads[i].m_IsRunning == 0) 
     { 
      g_Threads[i].m_IsRunning = 1; 
      ++g_Counter; 

      pthread_attr_t attr; 
      pthread_attr_init(&attr); 
      pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 
      pthread_create(&g_Threads[i].m_ID, &attr, thrFunc, &g_Threads[i]); 
      pthread_attr_destroy(&attr); 

      break; 
     } 
    } 
    pthread_mutex_unlock(&g_Mtx); 
} 

int main (int argc, char * argv[]) 
{ 
    pthread_mutex_init(&g_Mtx, NULL); 
    pthread_cond_init(&g_Cond, NULL); 
    g_Counter = 0; 

    for (int i = 0; i < 64; ++i) 
     createThread(); 

    pthread_mutex_lock(&g_Mtx); 
    while (g_Counter != 0) 
    { 
     pthread_cond_wait(&g_Cond, &g_Mtx); 
    } 
    pthread_mutex_unlock(&g_Mtx); 

    pthread_mutex_destroy(&g_Mtx); 
    pthread_cond_destroy(&g_Cond); 

    return 0; 
} 

Antwort

0

Das Leck Sie sehen, ist, weil der Abschluss Thread den Mutex-geschützten Fadenzähler dekrementiert, und Pausen für eine Sekunde, bevor der Thread beendet tatsächlich.

Der Hauptausführungsthread wird sofort sehen, dass der Thread-Zähler 0 erreicht und beendet, bevor die tatsächlich gelösten Threads beendet wurden. Jeder laufende Thread, selbst ein gelöschter Thread, verbraucht ein wenig internen Speicher, der nicht freigegeben wird, bis der Thread tatsächlich beendet wird. Dies ist das Leck, das Sie sehen, von Ausführungsthreads, die nicht beendet wurden, bevor der Hauptausführungsthread gestoppt wurde.

Dies ist nicht die Art von Leck, über die Sie sich Sorgen machen müssen. Es ist ziemlich ärgerlich und macht das Debugging schwierig, richtig.

In der Vergangenheit habe ich einen Ansatz in einer Framework-Klassenbibliothek gewählt, die ich vor einiger Zeit geschrieben habe. Ich habe überhaupt keine abgetrennten Threads verwendet, aber alle Threads waren verknüpfbare Threads. Das Framework startete einen Singleton-Hintergrundthread, dessen einzige Aufgabe join() der beendeten Threads war. Dann stellt jeder vom Framework gestartete Thread seine eigene Thread-ID für den Singleton-Hintergrund-Thread kurz vor dem Ende jedes Threads in eine Warteschlange.

Der Nettoeffekt entsprach den abgelösten Fäden. Ich könnte jeden Thread starten und mir keine Sorgen machen, dass ich mich ihm anschließe. Es wird der Job des Hintergrundthreads sein. Das Framework würde dem Hintergrund-Thread signalisieren, sich selbst zu beenden und ihm beizutreten, bevor er beendet wird. Also, wenn alles gut geht, wird es keine gemeldeten Speicherlecks geben, die der Thread-Unterstützung zugerechnet werden können.

+0

Danke für die Info, aber gibt es irgendwelche "saubere" Möglichkeit, das Leck zu verhindern, nur durch Bearbeiten des obigen Codes? – guderkar

+0

Nein. Die einzige Möglichkeit zu wissen, dass alle Ressourcen, die von einem Thread verwendet werden, freigegeben werden, besteht darin, sie beizutreten. Zwischen der letzten Aktion, die in einem Thread ausgeführt wurde, und dem Zeitpunkt, zu dem der Thread tatsächlich beendet wurde und alle Ressourcen freigegeben haben, wird es immer eine Race-Bedingung geben. –

+0

Vielen Dank, mein Herr. – guderkar