c++ 使用析构函数的线程联接

w8biq8rn  于 2022-12-20  发布在  其他
关注(0)|答案(4)|浏览(126)

这是我问题的延续:Thread creation inside constructor
现在我已经成功地在构造函数中创建了一个线程,我知道它必须被连接,因为我正在开发一个API,我对主函数没有控制权,所以我不能在那里连接它。
考虑到类的示例化对象将具有应用程序的生命周期,在类析构函数中加入线程是否正确?

kmb7vmvb

kmb7vmvb1#

你可以这样做。但是,你是真的对启动一个新线程的 * 机制 * 感兴趣,还是对异步执行某个任务的 * 效果 * 感兴趣?如果是后者,你可以转向更高级别的async机制:

#include <iostream>
#include <future>

void bar()
{
    std::cout << "I'm bar" << std::endl;
}

class foo
{
public:
    foo() :
        m_f(std::async(
            std::launch::async,
            bar))
    {

    }

    ~foo()
    {
        m_f.get();
    }

private:
    std::future<void> m_f;
};

int main ()
{
    foo f;
}
  • 你在构造函数中请求异步启动bar,你不关心自己管理线程--让库来处理。
  • 将生成的future放入成员中。
  • 在dtor中,get代表未来。
km0tfn4u

km0tfn4u2#

您已经遇到了C++ RAII的缺点之一:析构函数不能轻易地报告错误,析构函数也不能优雅地失败,因为它们没有返回值,抛出异常是bad idea
那么如果另一个线程没有响应停止请求,析构函数能做什么呢?它可以等待更长时间,或者猛烈地破坏另一个线程,或者让它继续运行,这些都不是很好的选择。然后它可以忽略这种情况,只是记录它,或者抛出异常,尽管应用程序有立即终止的风险,这也不是一个很好的选择集。
所以你至少有三个选择

  • 被联接的线程是已知的行为良好的,所以你知道它会在被请求时立即终止,并且在析构函数中联接是安全的。风险是,如果线程没有终止,程序将在联接时挂起。
  • 您确定析构函数中可用的错误处理选项(如上所述)是足够的,并且在析构函数中加入是可以的。您必须向析构函数添加错误检测和处理代码(例如超时)。
  • 提供一个单独的“close”方法,该方法可能接受timeout参数,然后返回错误值或在失败时抛出异常。

对于线程,无法立即终止的线程通常可以被视为类似于segfault的编程错误,因此您可以选择使用helpful终止应用程序(对开发人员)诊断消息(上面的第二个要点),或者让程序挂起(上面的第一点)。但是这有点冒险,因为如果继续下去,你需要创建一个不能很快终止的线程(它正在执行阻塞系统调用,或者它必须通知网络连接的另一端,这可能会很慢),在锁定设计之前考虑如何解决这个问题是一个好主意。

blpfk2vs

blpfk2vs3#

当然,你可以这样做。只是要确保线程将存在,否则你的程序将永远挂在该联接。

smtd7mpg

smtd7mpg4#

我提出了一个线程模式,我发现它可以处理C++中关于在类中运行线程的所有奇怪情况。
http://chrisd.nl/blog/how-to-run-threads/

相关问题