2017-09-13 10 views
3

vectorthreadのC++プログラムです。スレッド完了時にスレッドからベクトルを削除する

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

次に、スレッドを作成してvectorにプッシュします。私はthreadListvectorときlambda function終了の実行からthreadを削除するにはどうすればよい

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


編集

私は多少の溶液を作ってみました。スレッドlambda functionが返される前に、vectorを繰り返してIDの一致をthis_thread::get_id()にします。

Visual Studioで1行ずつデバッグすると、一致するものが見つかってerase関数が実行されますが、threadList.erase(threadList.begin() + index);が実行されるとすぐにスレッドのdeconstructor関数で処理されない例外が発生します。

私はこのエラーを複製する小さなコードを書いています。

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

ラムダは、ベクトルから 'std :: thread'を取り除くことができます(これは、' std :: mutex'などのように 'ベクトル'を並行アクセスから保護することを意味します)。あるいは、ラムダが何らかの方法で 'vector'を所有するスレッドにシグナルを送るようにして、そうする時間があるときにそのスレッドが' std :: thread'を取り除かせるようにすることができます。あるいは、所有するスレッド(または別の監視スレッド)に 'std :: thread'を単に' join() 'させ、終了時に削除することができます。 –

+1

'join()'スレッドを最初に実行してから、それをベクトルから完全に100%同一の方法で削除します。他のベクトルから何かを削除します。ベクトルは、 'std :: thread'を含んでいるからといって、その値を追加したり削除したりするという点で、動作が異なっていません。 –

+0

std :: vector :: erase() – Les

答えて

2

1つのオプションは、終了時にラムダが非同期スレッドを削除することです。また

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

@Acidic:意図的。 "*制御がlock_guardオブジェクトが作成されたスコープから離れると、lock_guardが破壊され、mutexが解放されます。*" 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(); 

スレッドは結合できないので、デストラクタを呼び出すことは安全です。 この場合、同期は避けられません。私の例では、すべてのスレッドを結合するために使用されています。スレッドのベクトルがある場合は、ベクトルへのアクセスを同期させる必要があります。

関連する問題