#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完成了做什么 仍在运行?为什么
完成后如何正确地标记?我不想坐在那里等待它,我只是想在完成后得到通知。
答案 0 :(得分:4)
此示例中的问题是dostuff
有两个实例,因此operator()
中设置为false的版本与main中的版本不同。
来自thread management documentation:
通过将可调用的可调用类型的对象传递给构造函数来启动新线程。然后将该对象复制到内部存储中,并在新创建的执行线程上调用。如果不能(或不能)复制对象,则可以使用boost :: ref传入对函数对象的引用。在这种情况下,Boost.Thread的用户必须确保引用的对象比新创建的执行线程更长。
如果您不想复制该对象,请使用boost::ref
:
thread t(boost::ref(doer), 4);
答案 1 :(得分:2)
答案 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信号之后),以确保在释放任何资源之前,子线程确实已经死了...否则,在子线程发出信号但线程清理例程完成之前,您冒着释放资源的主线程的竞争条件的风险。