1
#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 完成后如何正确标记?我不想坐等它,我只想在它完成时得到通知。

4

4 回答 4

4

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

线程管理文档

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

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

thread t(boost::ref(doer), 4);
于 2010-05-28T00:30:20.927 回答
2

你不能假设线程会通过睡眠完成。

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

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

于 2010-05-28T00:10:36.467 回答
1

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

带参数的线程构造函数

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

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

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

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

于 2010-05-28T00:27:52.477 回答
0

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

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

于 2010-05-28T00:16:11.103 回答