有没有一种可靠的方法来强制线程在C ++中停止? (特别是分离的)

时间:2016-05-17 16:11:38

标签: c++ multithreading c++11

我最近在C ++ 11中使用线程。现在我正在考虑如何强制停止一个线程。我无法在stackoverflow上找到它,也尝试了这些。

  • 每个帖子一个变量:不太可靠
  • 在主线程中返回:我必须强制退出只有一个

我没有更多的想法。我听说过WinAPI,但我想要一个便携式解决方案。 (这也意味着我不会使用fork())

你能告诉我一个解决方案吗?我真的很想这样做。

2 个答案:

答案 0 :(得分:6)

在C ++中强制关闭线程的一个最大问题是RAII违规。

当一个函数(以及随后的一个线程)正常完成时,它所保存的所有东西都被函数/线程创建的对象的析构函数清理干净。

记忆得到释放,
OS资源(句柄,文件描述符等)被关闭并返回到OS 锁正在解锁,因此其他线程可以使用它们保护的共享资源 执行其他重要任务(例如更新计数器,记录等)。

如果你粗暴地杀死一个线程(例如,在Windows上通过TerminateThread),实际上不会发生这些线程,并且程序处于非常危险的状态。

可以使用的一个(不那么)常见模式是注册一个“取消令牌”,如果其他线程要求,您可以监视并正常关闭该线程(一个TPL / PPL)。

之类的东西
auto cancellationToken = std::make_shared<std::atomic_bool>();
cancellationToken->store(false);

class ThreadTerminator : public std::exception{/*...*/};

std::thread thread([cancellationToken]{
  try{
    //... do things
    if (cancellationToken->load()){
       //somone asked the thred to close
       throw ThreadTerminator ();
    }
    //do other things...
    if (cancellationToken->load()){
       //somone asked the thred to close
       throw ThreadTerminator ();
    }
   //...

  }catch(ThreadTerminator){
    return;
  }

});

通常,人们甚至不为一个小任务打开一个新线程,最好将多线程应用程序视为并发任务和并行算法的集合。一个为一些长期持续的后台任务打开一个新线程,通常在某种循环中执行(例如,接受传入的连接)。

所以,无论如何,要求取消小任务的案例很少见。

tldr:

  

是否有可靠的方法强制线程在C ++中停止?

没有

答案 1 :(得分:1)

以下是我的大多数设计的方法:

想想两种线程:

1)小学 - 我打电话给主。

2)后续 - 由main或任何后续线程启动的任何线程

当我在C ++中启动std :: thread&#39;或者在C ++中启动posix线程时:

a)我提供所有后续线程访问布尔值&#34;完成&#34;,初始化为false。这个bool可以直接从main传递(或通过其他机制间接传递)。

b)我的所有线程都有一个常规的心跳&#39;通常带有posix信号量或std :: mutex,有时只有一个定时器,有时只是在正常的线程操作期间。

请注意心跳&#39;不是民意调查。

另请注意,检查布尔值非常便宜。

因此,只要主要关闭,它只会将完成设置为true并与后续线程连接。

有时main还会发出后续线程可能正在等待的任何信号量(在加入之前)。

有时,后续线程必须让自己的后续线程知道是时候结束了。

这是一个例子 -

主要启动后续主题:

std::thread*  thrd = 
    new std::thread(&MyClass_t::threadStart, this, id);
assert(nullptr != thrd);

请注意,我将this指针传递给此启动...在此类实例中是一个布尔m_done。

主要关闭:

在主线程中,当然,我所做的只是

m_done = true;

在后续线程中(在本设计中,所有线程都使用相同的关键部分):

   void threadStart(uint id) {
      std::cout << id << " " << std::flush; // thread announce

      do {

         doOnce(id);  // the critical section is in this method

      }while(!m_done);   // exit when done
   }

最后,在外部范围,main调用连接。

可能需要考虑的是 - 在设计线程系统时,您还应该设计系统关闭,而不仅仅是将其添加。