我是一个多线程初学者,我拧下面的代码:
#include <iostream>
#include <functional>
#include <thread>
#include <mutex>
#include <future>
#include <unistd.h>
using namespace std;
class Foo {
public:
Foo() {}
~Foo() { cout << "foo dtor" << endl; }
void first(function<void()> printFirst) {
printFirst();
}
void second(function<void()> printSecond) {
printSecond();
}
void third(function<void()> printThird) {
printThird();
}
};
int main() {
Foo foo;
thread t1([&foo] {
function<void()> print11 = [] { cout << "1" << endl; };
foo.first(print11);
});
thread t2([&foo] {
function<void()> print21 = [] { cout << "2" << endl; };
foo.second(print21);
});
thread t3([&foo] {
function<void()> print31 = [] { cout << "3" << endl; };
foo.third(print31);
});
sleep(2);
// t1.join();
// t2.join();
// t3.join();
return 0;
}
我得到了错误
“进程结束,退出代码为134(被信号6中断:符号)
如果取消注解这三行join()
,程序将正常退出。
我有一种感觉,这个错误是因为释放后再使用,但是无法解释原因。我想的是主线程在真正完成之前会休眠2秒,而在主线程休眠期间,t1、t2、t3应该已经完成了。因此,即使foo被销毁,three线程也不会在2秒后使用它。据我了解,免费问题后不应该使用。2有人能解释一下吗?3谢谢!
2条答案
按热度按时间o4hqfura1#
在我看来,这不像是释放后使用的问题,也不是争用条件,而是必需的行为,试图销毁一个处于可连接状态的线程对象(在这种情况下,你的线程对象也会处于可连接状态)是终止程序所必需的(N4835,§ [thread.thread.destr ]/1):
~线程();
1.如果
joinable()
,则调用terminate()
。否则,不起作用。[注意:在析构函数中隐式分离或联接joinable()
线程可能导致难以调试正确性(对于分离)或性能(对于联接)错误,这些错误仅在引发异常时遇到。因此,程序员必须确保在线程仍可联接时决不执行析构函数。-end note]线程从开始运行到
join()
ed或detach()
ed的时间都是joinable()
。总结
如果线程处于可连接状态,则销毁线程必须中止程序。要避免这种情况,请在销毁线程之前使用join()。
toiithl62#
当你
sleep(2)
的时候,操作系统没有义务运行你的其他线程。它可以让谷歌浏览器拥有这个时间片,或者它可以用它来做自己的后台任务,或者它可以只是坐在那里。你刚刚经历的“这个线程最多只能持续两秒,所以休眠就可以了”的逻辑叫做“竞争条件”。你有两个线程,你对这些线程中的事情发生的顺序做了很大的假设,而没有实际执行这些假设。实际上,你的线程进入了竞争状态:如果三个子线程赢得了比赛,那么你的程序运行良好,但是如果主线程赢得了比赛,那么你的程序表现出未定义的行为,如果你的程序有机会表现出未定义的行为,那么这意味着你的程序的行为是未定义的。
通过添加
join
调用,你可以强制执行你的假设,你要求主线程在其他三个线程完成之前不能退出,这是你之前隐含的假设,这使得你的程序的行为得到了定义。