使用析构函数进行线程连接
Thread joining using a destructor
这是我的问题的延续:
既然在构造函数中成功创建了线程,就知道必须加入了。由于我正在开发一个 API,我无法控制主要功能,所以我无法在那里加入它。
在 class 析构函数中加入线程是否正确,考虑到 class 的实例化对象将有一个应用程序的生命周期?
当然可以。只要确保该线程存在,否则您的程序将永远挂在该连接上。
你可以做到。但是,您是真的对启动新线程的机制感兴趣,还是对异步执行某事的效果感兴趣?如果是后者,可以移到更高级的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
未来。
我想出了一个线程模式,我发现它可以处理 C++ 中关于 类 个线程的所有奇怪情况。
你遇到了 C++ RAII 的缺点之一:析构函数不能轻易报告错误,析构函数不能优雅地失败,因为它们没有 return 值并且抛出异常是 bad idea.
那么如果另一个线程没有响应停止请求,析构函数可以做什么?它可以等待更多或暴力破坏另一个线程或离开它 运行,none 其中是非常好的选择。然后它可以忽略这种情况,只记录它,或者抛出异常,尽管有应用程序立即终止的风险,这又不是一组很好的选择。
所以,你至少有 3 个选择
- 已知加入的线程行为良好,因此您知道它会在请求时立即终止,并且在析构函数中加入是安全的。风险是,如果线程没有终止,程序将挂在连接上。
- 您确定析构函数中可用的错误处理选项(上面已解释)足够,并且在析构函数中加入是可以的。您必须将错误检测和处理代码添加到析构函数(例如超时)。
- 提供一个单独的 "close" 方法,它可能带有超时参数,然后是 returns 错误值或在失败时抛出异常。
对于线程,线程未能及时终止通常被认为是类似于段错误的编程错误,因此您可以选择终止应用程序并提供有帮助(对开发人员)的诊断消息(上面的第二个要点),或者只是让程序挂起(上面的第一个要点)。但这有点冒险,因为如果在路上你需要创建一个不能快速终止的线程(它正在做一个阻塞系统调用,或者它必须通知网络连接的另一端,这可能很慢) , 在锁定设计之前考虑如何解决这个问题是个好主意。
这是我的问题的延续:
既然在构造函数中成功创建了线程,就知道必须加入了。由于我正在开发一个 API,我无法控制主要功能,所以我无法在那里加入它。
在 class 析构函数中加入线程是否正确,考虑到 class 的实例化对象将有一个应用程序的生命周期?
当然可以。只要确保该线程存在,否则您的程序将永远挂在该连接上。
你可以做到。但是,您是真的对启动新线程的机制感兴趣,还是对异步执行某事的效果感兴趣?如果是后者,可以移到更高级的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
未来。
我想出了一个线程模式,我发现它可以处理 C++ 中关于 类 个线程的所有奇怪情况。
你遇到了 C++ RAII 的缺点之一:析构函数不能轻易报告错误,析构函数不能优雅地失败,因为它们没有 return 值并且抛出异常是 bad idea.
那么如果另一个线程没有响应停止请求,析构函数可以做什么?它可以等待更多或暴力破坏另一个线程或离开它 运行,none 其中是非常好的选择。然后它可以忽略这种情况,只记录它,或者抛出异常,尽管有应用程序立即终止的风险,这又不是一组很好的选择。
所以,你至少有 3 个选择
- 已知加入的线程行为良好,因此您知道它会在请求时立即终止,并且在析构函数中加入是安全的。风险是,如果线程没有终止,程序将挂在连接上。
- 您确定析构函数中可用的错误处理选项(上面已解释)足够,并且在析构函数中加入是可以的。您必须将错误检测和处理代码添加到析构函数(例如超时)。
- 提供一个单独的 "close" 方法,它可能带有超时参数,然后是 returns 错误值或在失败时抛出异常。
对于线程,线程未能及时终止通常被认为是类似于段错误的编程错误,因此您可以选择终止应用程序并提供有帮助(对开发人员)的诊断消息(上面的第二个要点),或者只是让程序挂起(上面的第一个要点)。但这有点冒险,因为如果在路上你需要创建一个不能快速终止的线程(它正在做一个阻塞系统调用,或者它必须通知网络连接的另一端,这可能很慢) , 在锁定设计之前考虑如何解决这个问题是个好主意。