【问题标题】:C++ terminate threadC++ 终止线程
【发布时间】:2015-11-22 18:48:16
【问题描述】:

我知道这个问题已被多次询问和回答,并且我知道结束线程的最佳方法是使用标志并在请求时退出线程函数。这也是我目前正在做的,但是我的问题是线程函数运行的时间很长,所以有时我需要等待几个小时,直到线程结束。我的线程函数看起来像这样:

void threadfunction()
{
    while(!exitRequested)
    {
        doSomeWork();
        object1.doSomeWork();
        object2.doSomeWork();
        while(somecondition)
        {
            object3.doSomeWork();
        }
        object4.doSomeWork();
    }
}

这只是一个示例,实际上代码看起来要复杂得多。但我想演示的是,我调用了几个类方法,这些方法可能需要几个小时才能完成(每个函数)。

所以我现在正在做的是检查函数之间是否请求退出(例如在object1.doSomeWork(); 和object2.doSomeWork(); 之间)但是正如我所说的函数调用可能需要几个小时,所以我需要检查是否在这些功能中要求退出。为了做到这一点,我需要将exitRequested 标志传递给这些函数,但在我看来这看起来不太好,可能有更好的解决方案。

我能想到的一个解决方案是通过抛出异常来创建这样的东西:

void threadfunction()
{
    try {
        while(!exitRequested)
        {
            ...
        }
    } catch (const ExitRequestException &e) {}
}

但是需要以某种方式引发异常。据我所知,我不能在另一个线程的线程中引发异常,对吧?

您有更好的解决方案吗?还是您认为我真的需要将exitRequested 标志传递给所有这些函数并污染我的代码?

【问题讨论】:

  • 您可以将一个引用(可能通过shared_ptr)传递给其构造函数中的每个不同工作对象的退出标志。
  • 将 exitRequested 标志(通过引用!)传递给函数。
  • @Jonathan 是的,你是对的,我也想过这个问题。但是,如果我这样做,我的代码再次污染,其中包含实际执行不需要的退出请求。我只是想知道是否有更好的解决方案。
  • 只需将功能分解为检查点/块/阶段或任何你称之为的东西。

标签: c++ multithreading kill terminate


【解决方案1】:

在谷歌搜索了一段时间后,我发现(并创建了)一个对我来说非常好的答案,尽管它只适用于 pthreads。对于非 pthread,我可以想象使用 here 描述的概念。

那么我现在在做什么:我正在向工作线程发送信号。此线程在信号处理程序中处理自定义信号并引发异常。此异常出现在线程函数的外部。通过使用这个概念,我的优势是抛出异常并展开堆栈,因此我可以关闭所有打开的资源。这是我的完整工作示例:

#include <thread>
#include <signal.h>
#include <unistd.h>
#include <iostream>

using namespace std;

//Custom exception which is used to stop the thread
class StopException {};

void sig_fun(int s)
{
    if(s == SIGUSR2)throw StopException();
}

void threadFunction()
{
    cout<<"Thread started"<<endl;
    try {
        while(true)
        {
            //Work forever...
            sleep(1);
        }
    } catch(const StopException &e) {
        cout<<"Thread interrupted"<<endl;
    }
    cout<<"Thread stopped"<<endl;
}

int main(int argc, char *args[])
{
    //Install Signal handler function
    signal(SIGUSR2, sig_fun);
    pthread_t threadObject;
    thread t([&threadObject]()
    {
        //Store pthread_t object to be able to use it later
        threadObject = pthread_self();
        threadFunction();
    });

    string temp;
    cout<<"Write something when you want the thread to be killed"<<endl;
    cin>>temp;

    //Send Signal to thread
    pthread_kill(threadObject, SIGUSR2);
    t.join();
}

【讨论】:

  • 我很确定,除非您的编译器明确允许,否则在信号处理程序中抛出异常是不正确的行为。即便如此,你也不能使用任何标记为 noexcept 的函数。
  • @MikeMB:非常感谢您的精彩评论!我没有想到这个!但根据这篇 (ibm.com/developerworks/library/l-cppexcep) 文章,它应该可以工作。
  • 那篇文章来自 2005 年,它早于 c++11(特别是 noexcept 和标准多线程),并且可能是在特定异常处理机制的假设下编写的(有不同的)。此外,本文仅提到同步信号,意思是在您处理它们的线程中引发的信号,这意味着由于某些操作(如浮点异常或分段错误)。但是,您尝试使用异步信号/异常。
  • 再一次,如果您的编译器文档指出,从信号处理程序中抛出异常很好,那么它可能适用于您的特定系统/编译器,但我几乎可以向您保证,这不是 ISO-符合 C++ 标准。 C++ 标准允许在信号处理程序内的信号处理程序和程序之间的唯一交互是使用std::atomic 或volatile std::sig_atomic_t variable or exit the program。 POSIX 允许更多,但没有提及异常,因为它们是 c++ 机制。
  • 谢谢MikeMB,我明白了
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多