c++ 我的代码退出时出现释放后使用错误,但我不知道为什么?

jgovgodb  于 2022-12-24  发布在  其他
关注(0)|答案(2)|浏览(133)

我是一个多线程初学者,我拧下面的代码:

#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谢谢!

o4hqfura

o4hqfura1#

在我看来,这不像是释放后使用的问题,也不是争用条件,而是必需的行为,试图销毁一个处于可连接状态的线程对象(在这种情况下,你的线程对象也会处于可连接状态)是终止程序所必需的(N4835,§ [thread.thread.destr ]/1):
~线程();
1.如果joinable(),则调用terminate()。否则,不起作用。[注意:在析构函数中隐式分离或联接joinable()线程可能导致难以调试正确性(对于分离)或性能(对于联接)错误,这些错误仅在引发异常时遇到。因此,程序员必须确保在线程仍可联接时决不执行析构函数。-end note]
线程从开始运行到join() ed或detach() ed的时间都是joinable()

总结

如果线程处于可连接状态,则销毁线程必须中止程序。要避免这种情况,请在销毁线程之前使用join()。

toiithl6

toiithl62#

当你sleep(2)的时候,操作系统没有义务运行你的其他线程。它可以让谷歌浏览器拥有这个时间片,或者它可以用它来做自己的后台任务,或者它可以只是坐在那里。
你刚刚经历的“这个线程最多只能持续两秒,所以休眠就可以了”的逻辑叫做“竞争条件”。你有两个线程,你对这些线程中的事情发生的顺序做了很大的假设,而没有实际执行这些假设。实际上,你的线程进入了竞争状态:如果三个子线程赢得了比赛,那么你的程序运行良好,但是如果主线程赢得了比赛,那么你的程序表现出未定义的行为,如果你的程序有机会表现出未定义的行为,那么这意味着你的程序的行为是未定义的。
通过添加join调用,你可以强制执行你的假设,你要求主线程在其他三个线程完成之前不能退出,这是你之前隐含的假设,这使得你的程序的行为得到了定义。

相关问题