如何在退出之前重新连接线程或等待线程完成

时间:2019-04-22 15:49:45

标签: c++ multithreading c++-standard-library stdthread

我有一个使用asio库连接到套接字的应用程序。我的主线程调用open()到套接字实现中,然后将其与主线程分离以继续执行。

调用thread::detach()时,无法再连接线程,因此调用者不知道线程何时完成执行。至少在我的应用程序中,这会导致异常关闭。资源未正确释放,仅在某些情况下会导致崩溃。是否可以重新加入分离的线程?我想尝试避免使用条件变量。

这是我的例子:

io_socket io = new io_socket();

// The call to thread::detach() is done within io_socket::open()
io->open();

// Let some things happen...
std::this_thread::sleep_for(std::chrono::seconds(20));

// Safely kills all operations and resources before delete
io->close();

// A hack solution to allow time for the detached thread to do what it needs to do
//std::this_thread::sleep_for(std::chrono::milliseconds(1000));

// Crashes if I don't allow the detached thread to safely close
delete io;

return EXIT_SUCCESS;

4 个答案:

答案 0 :(得分:2)

您无法重新附加已分离的std::thread。等待分离线程结束的唯一方法是使用某种原子/条件变量在完成时通知您。

也就是说,您可能首先不需要分离线程。您可以做的是为要驻留的线程创建存储(想到的是std::vector<std::thread>),然后在open中将新线程添加到该存储中。完成所有操作后,您将调用close,并让close遍历存储中的每个线程并在其上调用join。这将使close成为您的同步点,之后,您将知道所有线程都已结束并且可以安全地关闭应用程序。

答案 1 :(得分:1)

假设IO线程是由您编写的,则可以使用std::promisestd::future的组合来处理此问题,如下所示:

#include <chrono>
#include <thread>
#include <future>
#include <iostream>

using namespace std::chrono_literals;

void demo_thread (std::promise <bool> *p)
{
    std::cout << "demo thread waiting...\n";
    std::this_thread::sleep_for (1000ms);
    std::cout << "demo thread terminating\n";
    p->set_value (true);
}

int main ()
{
    std::promise <bool> p;
    std::thread t = std::thread (demo_thread, &p);
    t.detach ();

    // ...

    std::cout << "main thread waiting...\n";
    std::future <bool> f = p.get_future();
    f.wait ();

    std::cout << "main thread terminating\n";
}

Live demo

答案 2 :(得分:1)

  

是否可以重新加入分离的线程?

不。那会破坏detach()的全部目的。

t.detach()调用实际上并没有做任何必要的事情。唯一的目的是禁用安全机制。

通常,如果您没有detach()线程,则如果您允许在程序拥有thread之前销毁对象,则join()ed对象的析构函数将引发错误。它。这样做的唯一目的是帮助您避免一个常见的错误:这是为了防止main()例程在所有其他线程完成之前退出并终止程序。

t.detach()(仅用于 的目的)的目的是告诉图书馆,“谢谢,但是我知道我在做什么,我不想帮助,而我从不要打电话给t.join()


如果您希望程序调用{​​{1}},则不要调用t.join()

答案 3 :(得分:0)

NathanOliver提供了一个很好的答案,但是如果io->open()函数未返回对其创建的std :: thread对象的引用(如果分离,则它可能不会)。如果您直接使用Asio库,则我希望io->close()在删除io之前应正确处理线程的正常退出。但是,如果这是您实现的包装器,则您需要返回对open()中创建的线程对象的引用,或者更改您对close()的实现,以使其阻塞直到资源实际使用被释放。此外,如果这些方法是您自己实现的,那么open()中的分离是否有必要?