C++ boost.thread死锁和自删除
我正在使用C++ boost.thread死锁和自删除,c++,boost-thread,C++,Boost Thread,我正在使用boost::thread\u group创建(使用 线程组::创建线程())并分派线程。为了限制 最大线程数,在每个线程结束时,我移除线程 从线程组中删除线程本身(以便 决定是否需要创建新线程)。不管它挂在哪里 在创建和删除最后一个线程之间(比如 第9999页(共999页中的一页) 我的问题是: 可以从中删除线程吗 就像我做的那样?如果 不,最好的方法是什么 这个 为什么我的代码挂起 以下是相关代码: //1-创建和分派线程的代码 { //mutex for
boost::thread\u group
创建(使用
线程组::创建线程()
)并分派线程。为了限制
最大线程数,在每个线程结束时,我移除线程
从线程组
中删除线程本身(以便
决定是否需要创建新线程)。不管它挂在哪里
在创建和删除最后一个线程之间(比如
第9999页(共999页中的一页)
我的问题是:
- 可以从中删除线程吗 就像我做的那样?如果 不,最好的方法是什么 这个
- 为什么我的代码挂起
{
//mutex for map<thread_id, thread*> operations
boost::mutex::scoped_lock lk(m_mutex_for_ptr);
// create a thread for this->f(duplicate_hashes)
boost::thread* p = m_thread_group.create_thread(boost::bind(
&detectiveT<equal_predicate>::f,
this,
duplicate_hashes
));
// save the <thread_id,thread pointer> map for later lookup & deletion
m_thread_ptrs.insert(make_pair(p->get_id(), p));
// log to console for debug
cout << "thread created: "
<< p->get_id() << ", "
<< m_thread_group.size() << ", " m_thread_ptrs.size() <<
"\n";
}
{
//用于映射操作的互斥体
boost::mutex::scoped_lock lk(m_mutex_表示\u ptr);
//为此->f创建一个线程(重复\u散列)
boost::thread*p=m_线程组。创建线程(boost::bind(
&检测集::f,
这
重复散列
));
//保存地图以供以后查找和删除
m_thread_ptrs.insert(make_pair(p->get_id(),p));
//登录到控制台进行调试
既然创建/销毁非常昂贵,为什么不尝试回收线程呢
编写线程池类的代码并向其发送任务。如果池中没有更多可用线程,则该池将对任务进行排队;如果当前线程<最大线程,则创建线程;或者只使用可用线程
建议的实施:
找出你理想的线程数。这通常等于处理器的数量。
根据您希望的复杂程度,您可以一次在池中创建所有线程,或者在当前线程数<理想线程数且所有现有线程都忙于执行任务时添加线程
假设一次创建所有线程,则需要向每个线程传递一个辅助函数以执行。此辅助函数将等待任务变为可用,然后执行它们。因为函数要么执行任务,要么等待任务,所以它不会返回,线程也不会被销毁
线程池可以跟踪任务队列并管理指示队列中何时有可用任务的等待条件。每个线程辅助函数在等待条件下等待,当有可用任务时,它将唤醒并尝试执行该任务。
您必须进行一些同步;最简单的方法是尝试并找到一个可用的线程池实现,如Windows(我认为Vista+中的)或QtConcurrent中的线程池实现,它允许您通过任务、调用run并让操作系统/库担心一切
稍后编辑:
检查如果在调试器中运行程序,当程序挂起时,各个线程中发生了什么?从procexp.exe中,我可以看到所有线程都处于“Wait:UserRequest”状态。我怀疑在线程组内部锁和我引入的外部锁(即lk(m_mutex_for_ptr))之间发生了一些递归锁,但不确定如何。我曾经幸运地注释了这行“@Lightness Races in Orbit:只需在线程上调用detach()
,并删除其对象。这将使线程在退出时自动释放其资源(请参阅)。否则它会死锁连接自身或成为僵尸,因为当它退出时没有人会加入它。@Vlad:如果删除对象,则无需detach()
。我相信(a)会导致大量潜在死锁,使对象的地址对线程代码可见(b)当您还支持来自主线程的join_all()
操作时,线程将自己删除(您必须这样做)。此外,没有指定操作系统,因此仅使用pthread的保证是不够的。@LightnessRacesinOrbit:嗯,对了,仅仅因为没有指定操作系统,使用抽象古怪的包装就变成了在黑暗中行走。“Deatch”如果要拆下螺纹,请执行“join()”不必要的,并防止线程
类从析构函数调用join,或使用任何组包装器。我想你只需要检查一下实现在做什么。你能详细说明如何回收线程吗?我的经验是,线程的执行是通过ctor传递的,没有办法改变再次使用这个线程对象。感谢您的启发,我找到了Boost.Task,并将尝试如何利用它。虽然您没有直接回答我的问题,但您建议了一种更好的方法来解决我的问题。因此,我接受了您的答复。谢谢。
void f(list<map_iterator_type>& l)
{
Do_something(l);
boost::this_thread::at_thread_exit(boost::bind(
&detectiveT<equal_predicate>::remove_this_thread,
this
));
}
void remove_this_thread()
{
{
//mutex for map<thread_id, thread*> operations
boost::mutex::scoped_lock lk(m_mutex_for_ptr);
boost::thread::id this_id(boost::this_thread::get_id());
map<boost::thread::id, boost::thread*>::iterator itr;
itr = (m_thread_ptrs.find(this_id));
if(m_thread_ptrs.end() != itr)
{
// remove it from the control of thread_group
m_thread_group.remove_thread(itr->second);
// delete it
delete itr->second;
// remove from the map
m_thread_ptrs.erase(this_id);
// log to console for debug
cout << "thread erased: "
<< this_id << ", "
<< m_thread_group.size() << ", "
<< m_thread_ptrs.size() << "\n";
}
}
}