加入后如何删除线程?

how to erase a thread after joined it?

c++多线程程序,问题是: 我有一个线程向量,其中我 push_back 我创建的每个线程,我想做一种“窃取工作调度”,这样当一个线程被加入时,我就承担了他的工作终止后,我将其从线程向量中删除,然后我 push_back 一个新线程为他分配了另一个任务。 问题是,当我尝试在线程加入后擦除它们时,我得到了“terminate()”,所以我假设我正在擦除仍在工作的线程,即使我的目标是只擦除已经加入的线程。我哪里错了?

vector<thread> tids;
const int nw = atoi(argv[1]); //number of worker

//Just erase the thread that has been joined
void erasePosition(thread &t, vector<thread> &threads){
    for(int i=0;i<threads.size();i++){
        if(t.get_id()==threads[i].get_id()) {
            threads.erase(threads.begin()+i);
        }
    }
}


//Assign job to threads
for (int i = 0; i < nw; i++) {
        tids.push_back(thread(solveSubTree, ref(works[i]), ref(nw))); 
}

//
    for (thread &t : tids) {
        t.join();   
        erasePosition(t,tids);
        cout << " tids.size() = " << tids.size() << endl;       
    }

我看到程序正确执行直到我擦除中间线程,例如,如果我用 4 个线程执行程序,当我尝试擦除第二个线程时它调用“terminate()”,而如果我使用8个线程,当我尝试擦除第4个线程时它终止,也许它对你有用。

确切的错误是:在抛出 'std::system_error' 的实例后调用终止 what(): 无效参数

for (thread &t : tids) {

范围迭代是使用底层容器中的迭代器实现的。一个简单的 Google 搜索给你等效的代码,它从容器中获取开始和结束迭代器,然后迭代这个序列。

    erasePosition(t,tids);

此时,内部迭代器正在引用此向量中传递给 erasePosition() 的值。

erasePosition() 有效地 erase() 向量中的这个值。

但是,erase() 在向量 "invalidates iterators and references at or after the point of the erase, including the end() iterator" 中的值上。当然,这将包括 t 值的迭代器。从这一点开始,范围迭代成为未定义的行为。

胶囊总结:这与线程无关。无论你的向量中有什么,你都不能对向量进行范围迭代,删除向量中的值,然后继续你的范围迭代。您将需要以其他方式执行您的任务。这将适用于任何其他使迭代器无效的容器,从容器中删除的值(你的家庭作业将是弄清楚是否有任何类型的容器实际上允许它)。

这可能是也可能不是您崩溃的唯一原因。也可能有其他原因,但由于您没有提供 minimal reproducible example,因此无法确定。