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

Posted

技术标签:

【中文标题】有没有一种可靠的方法可以强制线程在 C++ 中停止? (尤其是分离的)【英文标题】:Is there a reliable way to force a thread to stop in C++? (especially detached ones) 【发布时间】:2016-05-17 16:11:37 【问题描述】:

我最近正在使用 C++11 中的线程。现在我正在考虑如何强制停止线程。我在***上找不到,也试过这些。

每个线程一个变量:不太可靠 在主线程中返回:我必须强制退出一个而不是全部

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

你能给我一个解决方案吗?我真的很想做。

【问题讨论】:

你的线程模型是什么?除非线程合作,否则 C++ 不提供任何强制关闭线程的方法。 没有。强制线程干净地停止是不可能的。有时有特定于平台的方法可以做到这一点,但它们总是不受欢迎,因为它们很危险。如果您在分配内存的过程中停止线程并破坏全局堆怎么办?如果你在它持有锁时停止它怎么办?等等。多线程需要精心设计。 至少我可以使用互斥锁,不是吗? 你将如何使用互斥锁?如果您解释了您的潜在问题,我们可能会提供更多帮助。 :-) 这不是一个真正的 C++ 问题。几乎可以肯定,您可以在平台 API 中对线程执行的任何操作都是 C 函数。 【参考方案1】:

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

当一个函数(以及随后的一个线程)优雅地结束时,它所持有的一切都会被函数/线程创建的对象的析构函数优雅地清理掉。

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

如果你残忍地杀死一个线程(例如,在 Windows 上被 TerminateThread 杀死),这些都不会真正发生,并且程序处于非常危险的状态。

可以使用的(不是那么)常见的模式是注册一个“取消令牌”,如果其他线程要求,您可以在其上监视并优雅地关闭线程(a la 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++ 中是否有可靠的方法强制线程停止?

没有。

【讨论】:

那么你的意思是每一种方法都不可靠?【参考方案2】:

这是我大部分设计的方法:

想想两种线程:

1) 主要 - 我称之为 main。

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


当我在 C++(或 C++ 中的 posix 线程)中启动 std::thread 时:

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

b) 我所有的线程都有一个常规的“心跳”,通常使用 posix 信号量或 std::mutex,有时只使用一个计时器,有时只是在正常线程操作期间。

请注意,“心跳”不是轮询。

还要注意检查布尔值真的很便宜。

因此,每当 main 想要关闭时,它只是将 done 设置为 true 并“加入”后续线程。

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

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


这是一个例子 -

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 调用连接。


也许要点是 - 在设计线程系统时,您还应该将系统设计为关闭,而不仅仅是添加它。

【讨论】:

以上是关于有没有一种可靠的方法可以强制线程在 C++ 中停止? (尤其是分离的)的主要内容,如果未能解决你的问题,请参考以下文章

强制停止正在执行的方法

强制停止正在执行的方法

Juc22_什么是中断interruptisInterruptedinterrupted方法源码解析如何使用中断标识停止线程

线程中断

JAVA-初步认识-第十四章-多线程-停止线程方式-定义标记

多核 C++ 线程