线程在完成后如何发出信号?

时间:2010-05-28 00:09:06

标签: c++ multithreading boost boost-thread

#include <iostream>
#include <boost/thread.hpp>
using std::endl; using std::cout;
using namespace boost;


mutex running_mutex;

struct dostuff
{
    volatile bool running;
    dostuff() : running(true) {}
    void operator()(int x)
    {
        cout << "dostuff beginning " << x << endl;
        this_thread::sleep(posix_time::seconds(2));
        cout << "dostuff is done doing stuff" << endl;
        mutex::scoped_lock running_lock(running_mutex);
        running = false;
    }
};

bool is_running(dostuff& doer)
{
    mutex::scoped_lock running_lock(running_mutex);
    return doer.running;
}

int main()
{
    cout << "Begin.." << endl;
    dostuff doer;
    thread t(doer, 4);

    if (is_running(doer)) cout << "Cool, it's running.\n";

    this_thread::sleep(posix_time::seconds(3));

    if (!is_running(doer)) cout << "Cool, it's done now.\n";
    else cout << "still running? why\n"; // This happens! :(

    return 0;
}

为什么输出上述程序:

  

开始..
  很酷,它正在运行。
  dostuff开始4
  dostuff完成了做什么   仍在运行?为什么

完成后如何正确地标记?我想坐在那里等待它,我只是想在完成后得到通知。

4 个答案:

答案 0 :(得分:4)

此示例中的问题是dostuff有两个实例,因此operator()中设置为false的版本与main中的版本不同。

来自thread management documentation

  

通过将可调用的可调用类型的对象传递给构造函数来启动新线程。然后将该对象复制到内部存储中,并在新创建的执行线程上调用。如果不能(或不能)复制对象,则可以使用boost :: ref传入对函数对象的引用。在这种情况下,Boost.Thread的用户必须确保引用的对象比新创建的执行线程更长。

如果您不想复制该对象,请使用boost::ref

thread t(boost::ref(doer), 4);

答案 1 :(得分:2)

你不能假设线程只是通过睡觉来完成。

您可以在该主题上调用join。这将等到线程完成然后恢复流程。

如果发生某个事件的线程之间的高级通知,您可以使用boost condition

答案 2 :(得分:1)

我猜你的问题实际上是代码中的错误。来自thread的Boost文档:

  

带参数的线程构造函数

     

模板&lt;类F,A1类,A2类,......&gt;
  线程(F f,A1 a1,A2 a2,...);

     

前提条件:
   F 且每个 A n 必须是可复制的或可移动的。

     

效果:
  好像是线程(boost :: bind(f,a1,a2,...))。 因此,f和每个 n 被复制到内部存储器中以供新线程访问。

所以,我认为线程正在修改自己的doer副本,而不是你正在检查其runnable状态的对象。

答案 3 :(得分:0)

真正的问题不是dostuff线程应该如何发送信号,而是主线程应该如何接收信号。我最喜欢的方法是使用socketpair()创建一个本地套接字连接,然后给一个套接字给子线程,另一个套接字给主线程。然后,两个线程可以使用套接字连接来相互通信。在你的情况下,你需要的只是让子线程在它退出之前在套接字上发送一个字节(或者只是关闭它的套接字文件描述符),这就足以将主线程从select()或者poll()或其阻塞的内容,让它知道子线程已完成其任务。

请注意,主线程仍然应该在子线程的线程ID上调用join()(在它接收到child-away-away信号之后),以确保在释放任何资源之前,子线程确实已经死了...否则,在子线程发出信号但线程清理例程完成之前,您冒着释放资源的主线程的竞争条件的风险。