3

POSIX 为线程取消类型指定了两种类型:PTHREAD_CANCEL_ASYNCHRONOUSPTHREAD_CANCEL_DEFERRED(由 设置pthread_setcanceltype(3))确定何时pthread_cancel(3)应该生效。根据我的阅读,POSIX 手册页对这些内容没有太多说明,但 Linux 手册页对以下内容进行了说明PTHREAD_CANCEL_ASYNCHRONOUS

线程可以随时取消。(通常情况下,收到取消请求后会立即取消,但系统不保证这一点。)

我很好奇系统的含义并不能保证这一点。我可以很容易地想象这发生在多核/多 CPU 系统中(在上下文切换之前)。但是单核系统呢:

  1. 当请求取消并启用取消(pthread_setcancelstate(3))并将取消类型设置为时,我们是否可以不立即取消线程PTHREAD_CANCEL_ASYNCHRONOUS
  2. 如果是,在什么条件下会发生这种情况?

我主要对 Linux (LinuxThreads / NPTL) 感到好奇,但也更普遍地对符合 POSIX 标准的查看此取消业务的方式感到好奇。

更新/澄清:这里真正的实际问题是在调用pthread_cancel()目标线程启用取消并设置为类型后立即销毁的资源的使用PTHREAD_CANCEL_ASYNCHRONOUS!所以关键是:在这种情况下,被取消的线程在上下文切换后继续正常运行的可能性很小(即使是很短的时间)?

感谢 Damon 的回答,减少了与下一个上下文切换相关的信号传递和处理问题。

Update-2:我回答了我自己的问题,指出这是一个不好的问题,底层程序设计应该在根本不同的概念级别上解决。我希望这个“错误”的问题对其他想了解异步取消奥秘的人有用。

4

2 回答 2

8

意思就是它所说的:它不能保证立即发生。这样做的原因是在标准中需要并考虑到实现细节的一定“自由”。

例如在Linux/NPTL下,取消是通过发送信号nr来实现的。32、线程在收到信号时被取消,这通常发生在下一次内核到用户的切换,或者下一次中断,或者时间片结束时(可能偶然是立即发生,但通常不是)。但是,当线程未运行时,永远不会收到信号。所以这里真正的问题实际上是不一定立即收到信号。

如果您考虑一下,甚至也不可能做很多不同的事情。由于您可以phtread_cleanup_push执行一些操作系统必须执行的处理程序(它不能只是使线程不存在!),因此线程必须运行才能被取消。无法保证任何特定线程(包括您要取消的线程)在您取消线程的确切时间正在运行,因此无法保证立即取消它。
当然,假设如果操作系统以阻塞调用线程并调度要取消的线程以便它执行其处理程序,并且仅在之后解除阻塞 pthread_cancel 的方式实现。但由于pthread_cancel没有指定为阻塞,这将是一个非常令人讨厌的惊喜。由于干扰了执行时间限制和调度程序的公平性,这在某种程度上也是不可接受的。

因此,无论您的取消类型是“禁用”,然后什么都不会发生。或者,它是“enable”,并且取消类型是“deferred”,那么线程在调用被列为取消点的函数时取消pthreads(7)
或者,它是“异步的”,那么如上所述,操作系统将在它认为合适的时候立即执行“某些事情”来取消线程——不是在一个精确的、明确定义的时间,而是“很快”。在 Linux 的情况下,通过发送信号。

于 2013-07-18T10:37:30.670 回答
0

如果您想知道异步取消何时发生,那么您正在做一些非常错误的事情。

  1. 遵循标准:通过故意创建或允许存在代码,其正确性取决于对平台的假设(单核、特定实现等),您正在吃掉脚下的土地。如果可能的话,遵循标准几乎总是更好(并在不可能时清楚地记录)。这个名字本身就暗示了异步PTHREAD_CANCEL_ASYNCHROUNOUS的含义,这与立即甚至几乎立即不同。原始海报明确指出单核,但是为什么要允许存在会以非确定性方式中断的代码,您的代码将在真正的并行机器(多核或 CPU)中运行,其中几乎不可能保证即时性(这将需要停止其他内核运行或等待上下文切换或您的操作系统 / 的其他一些可怕的黑客攻击CPU 不会支持支持您的非常规愿望)。 异步线程取消模式并不意味着保证立即取消线程。因此,即使可行,以这种方式使用它们也是一个非常令人困惑的黑客行为。

  2. 异步安全:如果您担心异步取消的机制,就会怀疑所讨论的线程(因为缺乏独立性)可能不是纯粹的计算或以异步取消安全的方式编写的。

    POSIX 仅将三个函数指定为异步取消安全:pthread_cancel(3)pthread_setcancelstate(3)pthread_setcancelmode(3)- 参见IEEE Std 1003.1, 2013 Edition, 2.9.5。这种取消模式只适用于不调用(纯计算除外)库函数的纯计算任务;如果线程设置为在默认的延迟取消模式下运行,则此类代码不会提供取消点。因此定义这种模式的基本原理

    可以通过在关键部分禁用取消来编写异步取消安全代码。但是库编写者(包括 POSIX 库实现者)一般不应该关心异步安全性,因为遵循一般约定,避免复杂性,甚至避免性能开销。因为库编写者不应该关心,所以除非另有明确说明,否则您永远不应期望异步安全。

    如果您的代码不是异步安全的(例如因为调用其他库,包括 POSIX/标准 C 库而没有暂时禁用取消或更改取消模式)并且发生异步取消,您可能会泄漏资源(内存等),留下不一致的状态和锁定的互斥锁死锁其他线程,并引发许多其他目前可以想象和不可想象的问题。(如果您使用 C++ 编写,由于 POSIX 线程取消与异常处理密切相关,您似乎还有其他问题需要处理。)

于 2013-07-27T05:00:53.143 回答