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

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

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

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

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

【问题讨论】:

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

标签: c++ multithreading c++11


【解决方案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 调用连接。


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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-27
    • 2011-07-11
    • 2015-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-05
    • 2014-06-14
    相关资源
    最近更新 更多