题 C ++,是每个线程的set_terminate本地吗?


应该 set_terminate/get_terminate 在C ++ 2011或C ++ 2003中为多个线程设置不同的终止异常处理器?

例如。如果我有程序并设置终止处理程序 func_1;然后我开始3个线程。什么是新线程中的终止处理程序?如果在每个线程中我将设置终止处理程序 func_2 在第一个帖子中, func_3 在第二个线程中等等。

N3242 (C ++ 2011草案)对此一无所知 [handler.functions] 或者在 [support.exception]/[exception.terminate]

PS:对于这些标准的任何流行实现,您可以回答C ++ 2011或C ++ 2003

PPS:有FCD评论... C ++ FCD评论状态Rev. 5 N3249(2011)

GB 71    18.6.2.4 / 18.8.2.2 / 18.8.3.2   

线程的安全性 std::set_new_handler()std::set_unexpected()std::set_terminate(),未指定,使得函数无法以线程安全的方式使用。

必须指定函数的线程安全保证,并且应提供新接口,以便以线程安全的方式查询和安装处理程序。

LWG 1365    接受修改

见纸 N3189


11
2018-03-12 16:40


起源


在发布C ++ 11之前,通过采用我的答案中引用的数据竞赛语言,解决了DR1365问题。 - ecatmur


答案:


17.6.4.7p4说:

打电话给 set_* 和 get_* 功能不得招致数据竞争。打电话到任何一个 set_* 函数应与后续调用同步 set_* 功能和相应的 get_* 功能。

这强烈暗示了 set_* 和 get_* 即使从不同的线程调用,函数也在相同的全局状态下运行。 18.8.3下的所有段落都讨论了“当前的处理函数“,没有提到线程;这表明处理函数是整个程序的属性;类似地,17.6.4.7具有:

2 - C ++程序可能在执行期间安装不同的处理函数[...]
  3 - C ++程序可以通过调用以下函数来获取指向当前处理函数的指针[...]

这些段落讨论 当前的处理函数 在程序的上下文中,表明它是程序范围而不是线程本地的。


10
2018-03-12 16:52



当set_ *和get_ *在线程本地状态下工作时,也不会有数据竞争。并且至少有3个实现具有记录的线程本地状态:ms,ibm,sun。 - osgx
@osgx C ++ 11有 thread_local 用于线程存储持续时间 - ecatmur
有MS VS 6和SUN(smth old): msdn.microsoft.com/en-us/library/aa272914(v=vs.60).aspx & amath.unc.edu/sysadmin/DOC4.0/c-plusplus/c%2B%2B_ug/...;两者都说关于线程本地 terminate:ms:“在多线程环境中,为每个线程单独维护终止函数。”; sun:“每个线程都可以设置自己的terminate()或unexpected()函数。在一个线程中调用set_terminate()或set_unexpected()只会影响该线程中的异常。”他们错了吗? - osgx
@osgx MS文档正在讨论C库函数 <eh.h>; C ++库函数记录在 msdn.microsoft.com/en-us/library/aa241196(v=vs.60).aspx。 Sun的文档就像你说的那样古老;在C ++ 11之前,C ++没有考虑线程,因此具有线程局部终止处理程序将是一个符合标准的扩展。 - ecatmur
msdn.microsoft.com/en-us/library/t6fk7h29.aspx 对于Visual Studio 2013非常明确地说“在多线程环境中,终止函数是为每个线程单独维护的。每个新线程都需要安装自己的终止函数。因此,每个线程都负责自己的终止处理。” - manylegged


在标准中它说

18.8.3.2 set_terminate [set.terminate]

terminate_handler set_terminate(terminate_handler f) noexcept;

1效果:将f指定的函数建立为当前处理函数 终止 异常处理。

[[noreturn]] void terminate() noexcept;

2效果:调用当前的terminate_handler函数。 [注意:默认的terminate_handler是 总是考虑 这个上下文中的可调用处理程序。 - 尾注]

你可以看到 terminate()  打电话给 当前 终止处理程序,在 set_handler 它非常明确地说它用于 终止 一个过程。当所有其他异常处理都失败时,无论从哪个线程运行,都会调用此方法。

只有一个终止处理程序,它总是从程序终止的任何地方调用。


3
2018-03-12 16:54



IBM说:“你可以通过提供一个调用pthread_exit()作为终止函数的函数来用线程级终止来覆盖它。这会终止线程,但不会终止进程。” - osgx
并且......终止“异常处理”意味着不是终止进程。单线程也可以终止。 - osgx
noreturn 对于单线程终止也是合法的。 - osgx
但这是全局终止处理程序引用它调用的线程(通过调用 pthread_exit),而不是特定于线程的处理程序。 - Daniel Frey
@osgx pthread_exit 在这种情况下仍然是程序范围的终止处理程序; IBM只是提供了一个扩展,允许终止处理程序只终止该线程。 - ecatmur


C2003没有线程,任何线程支持都是供应商扩展,因此只有供应商提供的文档才有答案。如果处理程序是每个线程,文档应该说。我知道没有实现它。

C ++ 2011没有提到终止处理程序的每线程性质。每个线程维护它是没有意义的,因为你不能在C ++ 11中杀死一个线程。并且有充分的理由(google kill + thread + c ++ 11)。所以无论你做什么,程序都必须终止。看起来有不同的方法来终止程序,具体取决于请求它的线程不是任何人需要的功能。


2
2018-03-12 17:27



Sun / Oracle做过/做过本地线程 set_terminate: Solaris Studio 12.2 “每个线程都可以设置自己的terminate()或unexpected()函数。在一个线程中调用set_terminate()或set_unexpected()只会影响该线程中的异常。” - osgx


该标准没有明确规定; [set.terminate] 只有国家

[...]当前处理程序函数,用于终止异常处理。

但是没有提到“当前”是全局还是每个线程。所以这取决于实施。

例如,在MSVC ++中: https://msdn.microsoft.com/en-us/library/t6fk7h29.aspx

在多线程环境中,为每个线程单独维护终止函数。每个新线程都需要安装自己的终止函数。因此,每个线程负责其自己的终止处理。


1
2018-02-14 04:11