【问题标题】:how a thread can signal when it's finished?线程如何在完成时发出信号?
【发布时间】:2010-05-28 00:09:05
【问题描述】:
#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 做完事了
仍在运行?为什么

dostuff 完成后如何正确标记?我确实想坐在那里等它,我只想在它完成时收到通知。

【问题讨论】:

  • 我知道你不想只是坐在那里。但是你应该在一个循环中检查is_running(可能也在循环中做其他工作)。完成后,您应该加入。否则就是资源泄漏。
  • 请注意,“volatile”并不真正意味着“可用于在线程之间传递消息”,尽管在大多数编译器中都是这样。建议使用适当的线程通信机制,如锁。此外,如果这实际上是应用程序的一部分,而不仅仅是示例代码,则 boost 的条件会为您提供一个超时等待,它可以代替您的睡眠。

标签: c++ multithreading boost boost-thread


【解决方案1】:

这个例子的问题是dostuff有两个实例,所以operator()中设置为false的版本与main中的不同。

来自thread management documentation

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

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

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

【讨论】:

    【解决方案2】:

    你不能假设线程会通过睡眠结束。

    你可以在线程上调用join。这将等到线程完成,然后恢复流程。

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

    【讨论】:

    • @Kyle:这只是我回答的一部分。
    【解决方案3】:

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

    带参数的线程构造函数

    模板
    线程(F f,A1 a1,A2 a2,...);

    前提条件:
    F和每个An必须是可复制或可移动的。

    效果:
    好像线程(升压::绑定(f,a1,a2,...))。 因此,f 和每个 an 都被复制到内部存储中以供新线程访问。

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

    【讨论】:

      【解决方案4】:

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

      请注意,主线程仍应在子线程的线程 ID 上调用 join()(在收到子线程离开信号后),以确保子线程真的死了,然后再释放任何资源...否则,您将面临主线程在子线程发出信号之后但在线程清理例程完成之前释放资源的竞争条件。

      【讨论】:

        猜你喜欢
        • 2014-08-07
        • 2018-07-25
        • 1970-01-01
        • 2015-11-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-12
        • 1970-01-01
        相关资源
        最近更新 更多