2017-09-13 2 views
3

Ich habe eine vector von thread s in meinem C++ - Programm.Entfernen Sie Thread aus Vektor nach Thread-Abschluss

std::vector<std::thread> threadList; 

I schaffen dann ein Gewinde und schieben es in die vector.

threadList.push_back(std::thread([]() { ... })); 

Wie kann ich die thread vom threadListvector wenn die lambda function beendet Ausführung entfernen?


bearbeiten

ich mit ein wenig von einer Lösung zu kommen haben; Bevor der Thread lambda function zurückkehrt, iteriert er durch vector, um eine Übereinstimmung in ID mit this_thread::get_id() zu finden.

Durch Visual Studio Debuggen Zeile für Zeile, ich sehe, dass es eine Übereinstimmung in ID findet und die erase Funktion ausgeführt wird, aber sobald threadList.erase(threadList.begin() + index); ausgeführt wird, ich komme eine nicht behandelte Ausnahme accross am Deconstructor Funktion Thread.

Ich habe ein kleines Stück Code geschrieben, der diesen Fehler repliziert.

vector<thread> threadList; 

threadList.push_back(thread([]() { 
    Sleep(1000); 
    threadList.erase(threadList.begin()); 
})); 

Sleep(2000); 

//for_each(threadList.begin(), threadList.end(), mem_fn(&thread::detach)); 
//threadList.clear(); 

Dieser Code ergibt den folgenden Screenshot.

enter image description here

+0

Das Lambda kann den 'std :: thread' aus dem Vektor entfernen (was bedeutet, dass der' Vektor' vor dem gleichzeitigen Zugriff geschützt wird, zB mit einem 'std :: mutex'), bevor er beendet wird. Oder Sie können das Lambdasignal den Thread, der den 'vector' besitzt, signalisieren lassen und diesen Thread den' std :: thread' entfernen lassen, wenn es Zeit dafür hat. Oder Sie können den besitzenden Thread (oder einen anderen Überwachungsthread) einfach 'join()' den 'std :: thread' haben und ihn entfernen, wenn er fertig ist. –

+1

'Join()' den Thread zuerst, dann entfernen Sie es aus dem Vektor in genau, 100% identische Weise würden Sie etwas von einem anderen Vektor entfernen. Ein Vektor verhält sich nicht anders, wenn er Werte hinzufügt oder entfernt, nur weil er 'std :: threads' enthält. –

+0

std :: vector :: erase() – Les

Antwort

2

Eine Möglichkeit ist, die den Faden entfernen lambda asynchron haben, wenn austritt. Zum Beispiel:

std::vector<std::thread> threadList; 
std::mutex threadMutex; 

... 

void removeThread(std::thread::id id) 
{ 
    std::lock_guard<std::mutex> lock(threadMutex); 
    auto iter = std::find_if(threadList.begin(), threadList.end(), [=](std::thread &t) { return (t.get_id() == id); }); 
    if (iter != threadList.end()) 
    { 
     iter->detach(); 
     threadList.erase(iter); 
    } 
} 

... 

{ 
    std::lock_guard<std::mutex> lock(threadMutex); 
    threadList.push_back(
     std::thread([]() { 
      ... 
      std::async(removeThread, std::this_thread::get_id()); 
     }) 
    ); 
} 

Alternativ:

std::vector<std::thread> threadList; 
std::mutex threadMutex; 

... 

void removeThread(std::thread::id id) 
{ 
    std::lock_guard<std::mutex> lock(threadMutex); 
    auto iter = std::find_if(threadList.begin(), threadList.end(), [=](std::thread &t) { return (t.get_id() == id); }); 
    if (iter != threadList.end()) 
    { 
     iter->join(); 
     threadList.erase(iter); 
    } 
} 

... 

{ 
    std::lock_guard<std::mutex> lock(threadMutex); 
    threadList.push_back(
     std::thread([]() { 
      ... 
      std::thread(removeThread, std::this_thread::get_id()).detach(); 
     }) 
    ); 
} 

Alternativ:

std::vector<std::thread> threadList; 
std::mutex threadMutex; 

std::list<std::thread::id> threadFreeList; 
std::mutex threadFreeMutex; 
std::condition_variable threadFreeCV; 

std::thread monitor([]() { 
    while (... /* app is not terminated */) 
    { 
     std::unique_lock<std::mutex> lock(threadFreeMutex); 
     threadFreeCV.wait(lock); 

     std::lock_guard<std::mutex> lock2(threadMutex); 
     auto iter = threadFreeList.begin(); 
     while (iter != threadFreeList.end()) 
     { 
      auto id = *iter; 
      auto found = std::find_if(threadList.begin(), threadList.end(), [=](std::thread &t) { return (t.get_id() == id); }); 
      if (found != threadList.end()) 
      { 
       found->join(); 
       threadList.erase(found); 
      } 
      iter = threadFreeList.erase(iter); 
     } 
    } 
}); 

... 

{ 
    std::lock_guard<std::mutex> lock(threadMutex); 
    threadList.push_back(
     std::thread([]() { 
      ... 
      std::unique_lock<std::mutex> lock(threadFreeMutex); 
      threadFreeList.push_back(std::this_thread::get_id()); 
      threadFreeCV.notify_one(); 
     }) 
    ); 
} 
+0

Sie sperren den Mutex, aber entsperren ihn nie ... ist das ein Fehler in Ihrem Code oder absichtlich? – Acidic

+1

@Acidic: absichtlich. Die RAII-Semantik kümmert sich um das Entsperren: "* Wenn die Kontrolle den Bereich verlässt, in dem das Objekt lock_guard erstellt wurde, wird der lock_guard zerstört und der Mutex freigegeben. *" STL-Klassen basieren auf den Prinzipien von RAII. –

+0

In meinem Projekt habe ich Code unterhalb der 'threadList.push_back'-Anweisung, aber immer noch im Bereich. Sollte ich in diesem Fall entsperren? – Acidic

0

Warum brauchen Sie diesen Vektor der Fäden, wenn man sie lösen kann?

// Scope that outlives the threads 
boost::barrier out_barrier(N_threads+1); 

... 

// Starting the threads 
for(int i = 0; i < N_threads; i++) { 
    std::thread th([&out_barrier]() { 
     ...do the job... 
     out_barrier.wait(); 
    }); 
    th.detach(); 
} 

... 

// Wait for threads to finish 
out_barrier.wait(); 

Die Threads können nicht verknüpft werden, daher kann der Destruktor sicher aufgerufen werden. Die Synchronisation ist in diesem Fall nicht zu vermeiden. In meinem Beispiel wird es verwendet, um alle Threads zu verbinden, und wenn Sie einen Vektor von Threads haben, müssen Sie den Zugriff auf den Vektor synchronisieren, so dass alles gleich ist.

Verwandte Themen