如何在退出前重新附加线程或等待线程完成

How to reattach thread or wait for thread completion before exiting

我有一个使用 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;

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

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

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

假设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

Is it possible to rejoin the detached thread?

没有。那将破坏 detach().

的全部目的

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

通常情况下,如果您没有 detach() 一个线程,那么 thread 对象的析构函数将抛出一个错误,如果您允许在您的程序 [=14] 之前销毁该对象=] 它。这样做的唯一目的是帮助您避免一个常见错误:这是为了防止您的 main() 例程在所有其他线程完成之前退出并终止程序。

t.detach()的目的——唯一的目的——是告诉图书馆,“谢谢,但我知道我在做什么,我不需要帮助,而且我 永远不会 会打电话给 t.join()


如果您希望程序调用 t.join(),则不要调用 t.detach()