c++ - 如果没有加入则中断线程

标签 c++ multithreading boost boost-thread

我正在寻找一种方法(最好使用 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 毫秒之前完成,我想尝试加入这些线程,如果在一定时间内未完成,是否有办法加入并中断?

编辑:我需要在超时前加入的原因:

我正在创建一个速度非常重要的服务器。不幸的是,我必须向其他服务器请求一些信息。所以我想并行进行这些调用,并尽快完成。如果服务器花费的时间太长,我只能忽略来自该服务器的信息,并在没有它的情况下继续。所以我的超时时间是我可以等待的最长时间。能够在收到所有响应时继续沉思,而不是等待时间超时计时器,这对我来说将是非常有益的。那么我的程序将:

-从客户端获取请求。

-解析信息。

创建线程

-将信息发送到多个其他服务器。

-从服务器获取信息。

-将来自服务器的信息放在共享队列中。

结束话题

-从共享队列中解析信息。

-返回信息给客户端

最佳答案

您想要使用的可能是一组作用域线程,并在超时后对所有剩余线程调用终止。不幸的是,线程组和作用域线程不能一起使用。

线程组类实际上是一个非常简单的容器:如果您还没有指向它的线程,则无法删除它的线程,并且您无法获得指向由该组创建的线程的指针。类 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

但是你必须做一些时间计算来跟踪收到通知后的剩余时间,并在剩下的时间继续 sleep 。这将完全取决于用于该任务的 Duration 类。

更新

从大局来看,我会尝试一种完全不同的方法:我不认为终止一个已经完成的线程是个问题,所以我会将它们全部留在组中,并使用组来创建它们,如您的代码所示。

但是,我会尝试在所有 线程完成后或超时后立即唤醒管理线程。这对于 thread_group 类单独提供的功能是不可行的,但它可以通过定制的信号量或 boost::barrier 的补丁版本来完成,以允许定时等等。

基本上,您为组中的线程数加上一个(主线程)设置了一个障碍,并让主线程时间等待它。每个工作线程执行其工作,完成后,将其结果发布到队列中,并在屏障上等待。如果所有工作线程都完成了他们的任务,每个人都将等待并触发屏障。

然后主线程(以及所有其他线程,但这并不重要)被唤醒,可以通过终止组并处理结果来继续。否则,它会在超时时被唤醒,并且无论如何都会做同样的事情。

boost::barrier的修补应该不会太难,你应该只需要复制wait方法并替换条件变量wait inside by a timed_wait (我没有看代码,虽然这个假设可能完全正确)。否则我为 this question 提供了一个示例信号量实现,这应该也不难修补。

一些最后的考虑:终止一个线程通常不是最好的方法。相反,您应该尝试向线程发出信号,让它们必须中止,并等待它们,或者以某种方式让它们将未完成的任务传递给辅助线程,辅助线程应该串行清理。然后您的线程组将准备好处理下一个任务,并且您不必一直销毁和创建线程,这是一项代价高昂的操作。它将需要在您的应用程序上下文中形式化任务的概念,并使线程在循环中运行以接受新任务并处理它们。

关于c++ - 如果没有加入则中断线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15929258/

相关文章:

c++ - 如何确保不会错过来自 QTcpSocket 的 readyRead() 信号?

c++ - 链接多个使用 boost 的项目时出现 LNK2005 错误

c - 如何在C中使用线程和数组

java - java应用程序中的进度条和线程错误

c++ - AVX2 float 比较并得到 0.0 或 1.0 而不是全 0 或全 1 位

c++ - 在 C++ 的子类中强制执行静态方法重载

c# - 设计线程安全类

boost - 具有空行和属性的基于行的解析器,如何忽略属性

c++ - 为什么 PyGILState_Release 抛出致命的 Python 错误

c++ - 如何使用 Boost log 设置每个日志源的严重性级别?