Sal*_*ram 8 c++ multithreading language-lawyer
C++20 草案[ except.handle]/12说:(添加了强调)
在具有线程存储持续时间的对象的析构函数中或在具有线程存储持续时间的命名空间范围对象的构造函数中引发的异常不会被线程的初始函数上的函数 try 块捕获。
和[ except.terminate]/1.10说(强调)
在某些情况下,为了不太微妙的错误处理技术而放弃了异常处理。[注1:这些情况是:
- [..]
- (1.10) 当线程的初始函数的执行通过异常退出时 [..]
什么是“线程的初始功能”?是main功能吗?它是[thread.thread.constr]/6std::invoke中指定的实现吗?或者是其他东西?
我问过某人,答案是线程的初始函数是该线程运行的第一个函数;并且线程运行的第一个函数始终是 的实现std::invoke。这是真的?
如果这不是真的,那么在上述标准措辞的上下文中“线程的初始函数”的实际定义是什么?
我问过某人,答案是线程的初始函数是该线程运行的第一个函数;并且线程运行的第一个函数始终是 的实现
std::invoke。这是真的?
这没有任何意义。
短语“初始函数”在标准中没有特定的定义,因此它应该按字面意思理解:最初由thread. 的构造函数std::thread/jthread 确实这么说:
新的执行线程执行
Run Code Online (Sandbox Code Playgroud)invoke(decay-copy(std::forward<F>(f)), decay-copy(std::forward<Args>(args))...)在构造线程中评估对衰减复制的调用。
然而,“仿佛”规则仍然适用。特定的实现并不需要专门使用std::invoke;它的行为必须“就像”它所做的那样。虽然允许用户为具有用户定义类型的标准库类模板提供专门化,但不允许他们专门化标准库函数模板,或在非常特定的情况之外重载它们。因此,用户无法(有效地)干扰 的含义std::invoke。
因此,实现根本不需要专门使用std::invoke。它可以使用与其等效的行为。
更重要的是……没关系。
您的程序无法更改调用您提供的函数后发生的情况thread。由于您无法影响该代码,因此“初始函数”措辞周围的任何行为都适用于您唯一可以控制的事情:您赋予它的函数的行为
因此,如果您给出的函数thread发出异常,则必然会触发有关“线程的初始函数”行为的子句,该子句不会捕获异常。无法导致该函数调用下面的某些内容捕获或以其他方式干扰此类子句。
因此,出于所有有意义的目的,“线程的初始函数”是“您传递的由thread/jthread的构造函数调用的任何函数”。
在 invoke(decay-copy(std::forward<F>(f)), decay-copy(std::forward<Args>(args))...
哪里f是可调用的以及您的初始函数。