使用pthread_cancel取消线程:良好做法或不好

时间:2011-01-21 15:43:01

标签: c++ linux pthreads

我在Linux(CentOS 5.3)上有一个C ++程序,它产生多个线程,这些线程处于无限循环中以执行工作并在某些时间内休眠。 现在我必须取消正在运行的线程以防新的配置通知进入并重新启动新的线程集,我已经使用了pthread_cancel。 我观察到的是,即使收到取消指示后线程也没有停止,即使睡眠完成后一些睡眠线程也会出现。

由于不需要这种行为,在上述场景中使用pthread_cancel会引发关于好坏练习的问题。

请在上述场景中评论pthread_cancel用法。

4 个答案:

答案 0 :(得分:43)

一般来说,线程取消并不是一个好主意。只要有可能,最好有一个共享标志,线程使用该标志来突破循环。这样,您将让线程执行在实际退出之前可能需要执行的任何清理。

在线程没有实际取消的问题上,POSIX规范确定了一组取消点(man 7 pthreads)。线程只能在这些点取消。如果您的无限循环不包含取消点,您可以通过调用pthread_testcancel添加一个取消点。如果已调用pthread_cancel,则此时将对其执行操作。

答案 1 :(得分:10)

如果您正在编写异常安全的C ++代码(请参阅http://www.boost.org/community/exception_safety.html),那么您的代码自然可以用于线程取消。 glibs throws C++ exception on thread cancel,以便你的析构函数可以进行适当的清理。

答案 2 :(得分:0)

我使用boost :: asio。

类似的东西:

struct Wait {
  Wait() : timer_(io_service_), run_(true) {}

  boost::asio::io_service io_service_;
  mutable boost::asio::deadline_timer timer_;
  bool run_;
};

void Wait::doWwork() {
  while (run) {
    boost::system::error_code ec;
    timer_.wait(ec);
    io_service_.run();
    if (ec) {
      if (ec == boost::asio::error::operation_aborted) {
        // cleanup
      } else {
        // Something else, possibly nasty, happened
      }
    }
  }
}

void Wait::halt() {
  run_ = false;
  timer_.cancel();
}

一旦你掌握了它,asio就是一个很棒的工具。

答案 3 :(得分:0)

您可以执行以下代码的等效操作。

#include <pthread.h>
#include <cxxabi.h>
#include <unistd.h>
...
void *Control(void* pparam)
{
    try
    {
        // do your work here, maybe long loop
    }   
    catch (abi::__forced_unwind&)
    {  // handle pthread_cancel stack unwinding exception
        throw;
    }
    catch (exception &ex) 
    {
        throw ex;
    }
}

int main()
{
    pthread_t tid;
    int rtn;
    rtn = pthread_create( &tid, NULL, Control, NULL );

    usleep(500);
    // some other work here

    rtn = pthtead_cancel( tid );
}