如果未加入则中断线程
Posted
技术标签:
【中文标题】如果未加入则中断线程【英文标题】:Interrupting threads if not joined 【发布时间】:2013-04-10 14:51:40 【问题描述】:我正在寻找一种方法(最好使用 boost 线程),如果线程尚未加入,则中断它。我启动了多个线程,并希望在 200 毫秒内结束其中的任何一个。我试过这样的东西
boost::thread_group tgroup;
tgroup.create_thread(boost::bind(&print_f));
tgroup.create_thread(boost::bind(&print_g));
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
tgroup.interrupt_all();
现在可以了,所有线程都在 200 毫秒后结束;但是,如果它们在 200 毫秒之前完成,我想尝试加入这些线程,如果在一定时间内没有完成,有没有办法加入和中断?
编辑:我需要在超时之前加入的原因:
我正在创建一个速度非常重要的服务器。不幸的是,我必须向其他服务器请求一些信息。所以我想并行进行这些调用,并尽快完成。如果服务器花费的时间太长,我必须忽略来自该服务器的信息,并在没有它的情况下继续。所以我的超时时间是我可以等待的最长时间。当收到所有响应时,能够继续沉思,而不是等待超时计时器,这对我来说是非常有益的。那么我的程序将是什么:
-从客户端获取请求。
-解析信息。
创建话题
-向多个其他服务器发送信息。
-从服务器获取信息。
-将来自服务器的信息放在共享队列中。
结束线程
-从共享队列中解析信息。
-将信息返回给客户端
【问题讨论】:
缺失的信息如何影响结果的计算?如果仍然缺少某些信息,您是否打算等待最长时间? 缺少信息影响不大。你可以认为它是一个出价。给定我提供的信息,每台服务器都会回复一个出价。如果他们没有及时归还任何东西,他们就无法出价。理想情况下,我希望所有服务器都响应,因为我将拥有最多的出价和最多的可用选择,但是如果服务器没有及时响应也没有问题。因此,只需切断我的开放连接并继续策略。 【参考方案1】:您想要使用的可能是一组作用域线程,并在超时后对所有剩余线程调用终止。不幸的是,线程组和作用域线程不能一起使用。
线程组类实际上是一个非常简单的容器:如果您还没有指向它的指针,则无法删除它的线程,并且您无法获得指向组创建的线程的指针。类 API 也没有提供太多。在您的情况下,这有点妨碍管理。
其余的解决方案依赖于在组外创建线程,并让每个线程在完成之前执行特定任务。它可以:
从组中删除自己, 然后将自己添加到另一个组中管理线程必须在后面的组上调用join_all
,并像以前一样处理前者。
using namespace boost;
void thread_end(auto &thmap, thread_group& t1, thread_group& t2, auto &task)
task();
thread *self = thmap[this_thread::get_id()];
t1.remove_thread(&self);
t2.add_thread(&self);
std::map<thread::id, thread *> thmap;
thread_group trunninggroup;
thread_group tfinishedgroup;
thread *th;
th = new thread(
bind(&thread_end, thmap, trunninggroup, tfinishedgroup, bind(&print_f)));
thmap[th->get_id()] = th;
trunninggroup.add_thread(th);
th = new thread(
bind(&thread_end, thmap, trunning_group, tfinishedgroup, bind(&print_g)));
thmap[th->get_id()] = th;
trunninggroup.add_thread(th);
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
tfinishedgroup.join_all();
trunninggroup.interrupt_all();
但是,如果您确实希望管理线程在线程实际发生时被通知线程结束(而且我不确定它是否有任何用处),这并不理想。获得通知的解决方案可能是:
如上所述进行组迁移 然后触发一个条件变量,管理线程在该变量上执行timed_wait
但是您必须进行一些时间计算以跟踪收到通知后的剩余时间,并在剩下的时间恢复睡眠。这将完全取决于用于该任务的 Duration 类。
更新
从大局来看,我会尝试一种完全不同的方法:我不认为终止一个已经完成的线程是一个问题,所以我会将它们全部留在组中,并使用组来创建它们,正如您的代码所展示的那样。
但是,我会尝试在所有线程完成后或超时后立即唤醒管理线程。这对于 thread_group
类单独提供的功能是不可行的,但可以通过自定义信号量或 boost::barrier
的修补版本来实现,以允许定时等待。
基本上,您为组中的线程数加一(主线程)设置障碍,并让主线程时间等待它。每个工作线程完成其工作,完成后,将其结果发布到队列中,并将wait
发布到屏障上。如果所有工作线程都完成了他们的任务,每个人都会等待并触发屏障。
然后主线程(以及所有其他线程,但没关系)唤醒并可以通过终止组并处理结果来继续。否则,它会在超时时被唤醒,并且无论如何都会这样做。
boost::barrier
的打补丁应该不会太难,你只需要复制wait
方法,把里面的条件变量wait
替换成timed_wait
即可(我没看代码,不过,这个假设可能是完全正确的)。否则我为this question 提供了一个示例信号量实现,它也应该不难修补。
最后一点考虑:终止线程通常不是最好的方法。相反,您应该尝试向它们发出中止线程的信号,并等待它们,或者以某种方式让它们将未完成的任务传递给应该连续清理的辅助线程。然后,您的线程组将准备好处理下一个任务,并且您不必一直销毁和创建线程,这是一项代价高昂的操作。它将需要在应用程序的上下文中形式化任务的概念,并使线程在循环上运行以获取新任务并处理它们。
【讨论】:
谢谢。我将研究作用域线程,看看这是否可行。我不需要使用线程组,我唯一的要求是我可以让线程几乎同时超时,但如果所有线程都完成后结束。如果可能的话,我宁愿不做时间跟踪,但如果我必须这样做,我想我也有。似乎作用域线程也是相当新的 boost,你知道我在升级我的 boost 版本时可以看看的任何好的例子吗? 更正了我的答案,以解决从它执行的可调用对象访问线程实例的问题。它涉及更多一点。我想您最好不要使用组容器,而是使用普通容器,并在超时时对每个剩余线程手动调用终止。有点粗糙,但此时 C++ 中的线程管理仍然很困难。也许你可以看看线程池。 不幸的是,我认为您的代码对我不起作用。我仍然有 200 毫秒的睡眠,除非我读错了。在考虑了更多之后,我可能最好使用deadline_timer,同时尝试join_all。如果它到达时间,我会让deadline_timer 中断thread_group。如果没有,我将取消计时器。我相信这应该有效。如果它不起作用,我将使用 timed_join 管理计时器,我认为,我只会计算从当前时间开始的 200 毫秒,然后对于之后的每个连接,我将从新的当前时间到结束时间进行定时连接. 我在回答的最后解决了这个问题。正如我所说,由于代码只迁移线程并在最后加入它们,因此您需要某种触发器来唤醒主线程并执行join
。请问你为什么要在超时前加入?无论如何,thread
实例不会消失。也许有一些计算结果要检索?
我明白了,对不起,我误读了你答案的结尾。我用我正在做的事情更新了我原来的帖子。如果您需要有关它的更多信息,请告诉我。【参考方案2】:
如果您使用的是最新的 Boost 和 C++11,请使用 try_join_for()
(http://www.boost.org/doc/libs/1_53_0/doc/html/thread/thread_management.html#thread.thread_management.thread.try_join_for)。否则,请使用timed_join()
(http://www.boost.org/doc/libs/1_53_0/doc/html/thread/thread_management.html#thread.thread_management.thread.timed_join)。
【讨论】:
可以将 timed_join 或 try_join_for 与 thread_group 结合使用。或者有没有一种好方法来设置多个单线程同时结束这些(我相信这些块)? @Eumcozboost::thread_group
的接口比boost::thread
少,并且它没有名为timed_join
或try_join_for
或try_join_until
的接口。以上是关于如果未加入则中断线程的主要内容,如果未能解决你的问题,请参考以下文章