从另一个取消提升线程

时间:2015-06-01 20:44:18

标签: c++ multithreading boost

有没有办法从另一个取消boost :: thread,如下所示?:

boost::thread* thread1(0);
boost::thread* thread2(0);

thread2 = new boost::thread([&](){
   //some expensive computation that can't be modified
  if(thread1)
    thread1->interrupt();  
});

thread1 = new boost::thread([&]() {
  //some other expensive computation that can't be modified
  if(thread2)
    thread2->interrupt();  
});

thread1->join();
thread2->join();

delete thread1;
delete thread2;

现在两个昂贵的计算都没有被打断。我认为连接将被视为中断点,主线程将在完成两个昂贵的计算之一后继续。

2 个答案:

答案 0 :(得分:5)

通常,没有可移植的方法让一个线程终止另一个线程,而没有来自被终止的线程的合作。这个问题偶尔会出现(看herehere - 虽然你的问题不完全重复)。

禁止线程被中断的合作(必须在通知时执行seppuku),如果你希望主线程在第一个线程终止后继续,你可以创建一个condition每个子线程结束时会触发它们。

此时,您可以让另一个线程继续运行(可能是detach),或者只是终止所有内容。

答案 1 :(得分:1)

符合POSIX标准的系统(例如Linux)的非便携式解决方案是在Boost线程pthread_cancel()上使用pthread_join() native_handle() 1}}成员,类型为pthread_t(同样,仅适用于POSIX兼容系统。我不能代表其他系统,如Windows)。

此外,您必须使用boost::scoped_thread而不是boost::thread,以便您可以覆盖" (不是在OO意义上)Boost在线程被销毁时将执行的连接/分离行为。这是必要的,因为当您在pthread_cancel上呼叫pthread_join然后boost::thread时,boost::thread对象仍然可以加入' (即boost::thread::joinable()返回true),因此析构函数将根据documentation显示未定义的行为。

尽管如此,如果在您的应用程序中需要一个依赖于平台的解决方案来取消这样的线程,我不确定使用boost::thread s可以获得多少收益在普通的pthread;不过,我想可能有一个用例。

这是一个代码示例:

// compilation: g++ -pthread -I/path/to/boost/include -L/path/to/boost/libs -lboost_thread main.cpp

#include <cstdio>
#include <pthread.h>
#include <boost/thread/scoped_thread.hpp>

typedef struct pthreadCancelAndJoin
{
    void operator()(boost::thread& t)
    {
        pthread_t pthreadId = t.native_handle();
        int status = pthread_cancel(pthreadId);
        printf("Cancelled thread %lu: got return value %d\n", pthreadId, status);

        void* threadExitStatus;
        status = pthread_join(pthreadId, &threadExitStatus);
        printf("Joined thread %lu: got return value %d, thread exit status %ld\n",
               pthreadId, status, (long)threadExitStatus);
    }
} pthreadCancelAndJoin;

void foo()
{
    printf("entering foo\n");
    for(int i = 0; i < 2147483647; i++) printf("f");  // here's your 'expensive computation'
    for(int i = 0; i < 2147483647; i++) printf("a");
    printf("foo: done working\n");  // this won't execute
}

int main(int argc, char **argv)
{
    boost::scoped_thread<pthreadCancelAndJoin> t1(foo);
    pthread_t t1_pthread = t1.native_handle();

    sleep(1);  // give the thread time to get into its 'expensive computation';
               //   otherwise it'll likely be cancelled right away

    // now, once main returns and t1's destructor is called, the pthreadCancelAndJoin
    //   functor object will be called, and so the underlying p_thread will be cancelled
    //   and joined

    return 0;
}

pthread_cancel()会在到达&#34;取消点时取消您的帖子&#34; (假设cancel type and cancel state处于默认值,这是boost::thread个对象的情况;请参阅pthreads man page以获取所有取消点的列表。您会注意到这些取消点包括许多较常见的系统调用,例如writereadsleepsendrecvwait等等。

如果您的计算费用昂贵,那么包括 任何 的最低级别的调用(例如,在代码示例中,printf最终调用write),它将被取消。

最重要的是,Valgrind报告此解决方案没有内存泄漏或内存错误。

最后,在你的问题中记下你的误解:

  

我认为连接将被视为中断点......

就此而言,

join或任何boost::thread中断函数仅被视为调用的线程的中断点 。由于您的主线程正在调用join(),因此主线程是遇到中断点的线程,而不是它尝试加入的线程。例如。如果您在某个主题中调用thread1.interrupt(),然后thread1调用thread2.join(),那么thread1就会被中断。