繁体   English   中英

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

[英]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 等待分离线程结束的唯一方法是使用某种原子/条件变量在完成时通知您。

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

假设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";
}

现场演示

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

不。那会detach()的整个目的。

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

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

t.detach()的目的是唯一的目的,它是告诉库:“谢谢,但是我知道我在做什么,我不想要帮助,我永远也不会打电话给我t.join()


如果要让程序调用t.join()则不要调用t.detach()

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

暂无
暂无

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

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