简体   繁体   English

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

[英]My code is exiting with use-after-free error but I don't know why?

I'm a multithreading beginner and I'm wring the below code:我是多线程初学者,正在编写以下代码:

#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;
}

And I'm getting the error我收到了错误

"Process finished with exit code 134 (interrupted by signal 6: SIGABRT) “进程以退出代码 134 结束(被信号 6 中断:SIGABRT)

If I uncomment the three join() lines, the program exit normally.如果我取消注释这三个join()行,程序将正常退出。

I have a feeling that the error is due to use after free, but cannot explain why.我有一种感觉,错误是由于在 free 之后使用,但无法解释原因。 What I'm thinking is the main thread will sleep 2 seconds before it really finishes, and during the main thread is sleeping, the t1, t2, t3 should already finish.我在想的是主线程会在它真正完成之前休眠 2 秒,并且在主线程休眠期间,t1、t2、t3 应该已经完成。 Hence, even if foo is destroyed, the three thread won't use it after 2 seconds.因此,即使 foo 被销毁,三线程也不会在 2 秒后使用它。 As far as I understand, it should not have use after free problem.据我了解,它不应该有 use after free 的问题。 Could anybody explain?有人能解释一下吗? Thanks!谢谢!

The operating system is under no obligation to run your other threads when you sleep(2) .当您sleep(2)时,操作系统没有义务运行您的其他线程。 It could let Google Chrome have that time slice, or it could use it to do its own background tasks, or it could just sit there on its thumbs.它可以让谷歌浏览器拥有那个时间片,或者它可以用它来完成自己的后台任务,或者它可以坐以待毙。

That logic you just went through of "This thread should only last two seconds at most, so sleeping will do it" is called a race condition .您刚刚经历的“这个线程最多只能持续两秒钟,所以睡觉就可以”的逻辑称为竞争条件 You've got two threads and you're making big assumptions about what order things in those threads will happen, without actually enforcing those assumptions.您有两个线程,您正在对这些线程中发生的事情的顺序做出重大假设,而没有实际执行这些假设。 Effectively, your threads enter into a race: if the three child threads win the race, then your program works fine, but if the main thread wins the race, then your program exhibits undefined behavior.实际上,您的线程进入了一场比赛:如果三个子线程赢得比赛,那么您的程序就可以正常工作,但如果主线程赢得比赛,那么您的程序就会表现出未定义的行为。 And if your program has a chance of exhibiting undefined behavior, then that means that your program's behavior is undefined.如果您的程序有可能表现出未定义的行为,那么这意味着您的程序的行为是未定义的。

By adding the join calls, you enforce your assumption.通过添加join调用,您可以强制执行您的假设。 You demand that the main thread cannot exit until the other three threads finish, which is what you were implicitly assuming before.您要求主线程在其他三个线程完成之前不能退出,这是您之前隐含的假设。 This makes your program's behavior defined.这使您的程序的行为得到定义。

This does not look to me like a use after free problem, and it's not a race condition either.在我看来,这不像是免费问题后使用,也不是竞争条件。 It's required behavior.这是必需的行为。 Attempting to destroy a thread object that is in a joinable state (which yours would be under the circumstances) is required to terminate the program (N4835, §[thread.thread.destr]/1):试图销毁处于可连接状态的线程对象(在这种情况下你的线程对象)需要终止程序(N4835,§[thread.thread.destr]/1):

~thread(); 〜线程();

  1. If joinable() , calls terminate() .如果是joinable() ,调用terminate() Otherwise, has no effects.否则,没有效果。 [Note: Either implicitly detaching or joining a joinable() thread in its destructor could result in difficult to debug correctness (for detach) or performance (for join) bugs encountered only when an exception is thrown. [注意:在其析构函数中隐式分离或加入joinable()线程可能导致难以调试正确性(对于分离)或性能(对于连接)错误,只有在抛出异常时才会遇到。 Thus the programmer must ensure that the destructor is never executed while the thread is still joinable.因此,程序员必须确保析构函数永远不会在线程仍然可连接时执行。 —end note] ——尾注]

A thread is joinable() from the time it starts to run until the time it is join() ed or detach() ed.一个线程从它开始运行到它被join() ed 或detach() ed 时都是joinable() () 。

Summary概括

Destroying a thread must abort the program if the thread is in a joinable state.如果线程处于可连接状态,则销毁线程必须中止程序。 To avoid this, join() the thread(s) before destroying them.为了避免这种情况,在销毁它们之前加入()线程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM