2017-09-13 69 views
3

我在我的C++程序中有vectorthread s。在線程完成時從線程移除線程

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

然後我創建一個線程並將其推入vector

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

我如何刪除從threadListvectorlambda function執行完畢的thread


編輯

我拿出幾分的解決方案;在線程lambda function返回之前,它會遍歷vector以找到與this_thread::get_id()的ID匹配。

通過Visual Studio逐行調試,我發現它在ID中找到匹配,並且執行了erase函數,但只要threadList.erase(threadList.begin() + index);被執行,我就會在線程的解構函數中處理未處理的異常。

我寫了一小段代碼來複制這個錯誤。

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(); 

此代碼導致下面的屏幕截圖。

enter image description here

+0

在退出之前,lambda可以從vector中移除'std :: thread'(這意味着在併發訪問中保護'vector',例如使用'std :: mutex')。或者,您可以讓lambda信號以某種方式擁有'vector'的線程,並且在有時間的時候讓該線程移除'std :: thread'。或者,您可以擁有自己的線程(或另一個監視線程),只需'join()'std :: thread'並在完成時將其刪除。 –

+1

'首先加入()'線程,然後以完全相同的方式從矢量中刪除它,您將從其他矢量中刪除某些東西。就添加或刪除值而言,矢量的行爲不同,只是因爲它包含'std :: thread's。 –

+0

std :: vector :: erase() – Les

回答

2

一種選擇是有退出時的拉姆達刪除線程異步。例如:

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()); 
     }) 
    ); 
} 

或者:

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(); 
     }) 
    ); 
} 

或者:

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

你鎖定互斥鎖,但從來沒有解鎖它......這是你的代碼或故意的錯誤? – Acidic

+1

@酸性:故意的。 RAII語義負責解鎖它:「*當控制權離開創建lock_guard對象的範圍時,lock_guard被銷燬並釋放互斥鎖。*」STL類基於RAII原則構建。 –

+0

在我的項目中,我在'threadList.push_back'語句下面有代碼,但仍在範圍內。我應該在這種情況下解鎖嗎? – Acidic

0

爲什麼你需要的線程這一載體時,你可以分離他們?

// 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(); 

線程不可連接,因此可以安全地調用析構函數。 在這種情況下,同步是不可避免的。在我的例子中,它用於連接所有線程,並且如果您有一個線程向量,則需要將訪問同步到向量,所以它們都是一樣的。