我有一个使用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;
假设IO线程由您编码,您可以使用std::promise
和std::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";
}
你不能重新连接你已经脱离的std::thread
。等待分离线程结束的唯一方法是使用某种原子/条件变量来通知你何时完成。
也就是说,您可能不需要首先分离线程。您可以做的是为线程创建存储(std::vector<std::thread>
浮现在脑海中),然后在open
中将新线程添加到该存储。一旦你完成了所有你打电话给close
并让close
通过存储中的每个线程并在其上调用join
。这将使close
成为您的同步点,之后您就知道所有线程都已结束,您可以安全地关闭应用程序。
是否有可能重新加入分离的线程?
不,这会打败detach()
的整个目的。
t.detach()
电话实际上并没有做任何必要的事情。它的唯一目的是禁用安全机制。
通常情况下,如果你没有detach()
一个线程,那么thread
对象的析构函数将抛出一个错误,如果你允许在你的程序有join()ed
它之前销毁该对象。唯一的目的是帮助您避免一个常见的错误:这是为了防止您的main()
例程在所有其他线程完成之前退出并终止程序。
t.detach()
的唯一目的---告诉图书馆,“谢谢,但我知道我在做什么,我不想要帮助,我永远不会打电话给t.join()
。
如果你想让你的程序调用t.join()
,那么不要调用t.detach()
。
NathanOliver提供了一个很好的答案,但是如果io->open()
函数没有返回对它创建的std :: thread对象的引用(如果它分离,它可能不会),那么他的解决方案可能会很难。如果您直接使用Asio库,我希望io->close()
应该在删除io
之前正确处理线程的优雅退出。但是,如果这是您实现的包装器,则需要在open()
中返回对创建的线程对象的引用,或者更改close()
的实现,以便它阻塞,直到资源实际被释放为止。此外,如果这些是自己实施的方法,那么open()
中的分离是否必要?