什么是取消点?

30

我试图理解 C++ 中的取消点是什么。我已经阅读了 man pageWhat are pthread cancellation points used for,但在某些方面仍感到困惑。例如,我正在使用文件的 write() 函数,显然这是一个取消点。因此,当我调用 write() 时,我可以看到另一个线程可能会开始处理,这通常发生在写入缓冲区已满并需要在 write() 能够成功/完成之前被清空的情况下。

但在我的看法中,这不是线程的取消,而只是暂时的阻塞/挂起,并且没有任何线程“清理”要做...

所以我的问题是,取消点与“阻塞点”有关系吗?它们真的是相同的东西,还是有一些区别?任何有关取消点的明确的“顶层”描述都将非常有用。


5
一般情况下,取消点是指控制流在任何返回调度程序的位置。 "取消" 的唯一可能含义是不再被安排运行,因此只有在您能够影响调度决策时才能取消某些内容。系统调用与调度程序形成自然的交互,尽管可能存在其他形式的交互。 - Kerrek SB
@KerrekSB 通过这个评论和Bogdan V的回答,我现在觉得这真的对我有意义,谢谢 :) - code_fodder
感谢@KerrekSB提供了一个清晰、简洁、扎实的解释,其中提到了调度程序。 - daparic
2个回答

33
当线程被操作系统中止时,它的状态会被保存,这并不意味着线程被取消。取消意味着在请求下终止线程,并特别希望在完成时让所有东西处于最终状态(例如,所有资源都被释放,所有处理程序都被更新等)。
你所说的阻塞可能发生在取消过程中。
例如:线程收到取消请求。操作系统将其排队,直到线程变为可取消。当线程变为可取消,并且正在执行取消点时,可以清除并取消线程。write函数是一个取消点,这意味着在执行此函数时,从操作系统的角度来看,可以安全地取消线程(所有相关资源的状态将保持一致)。
在取消过程运行时,操作系统可以随意阻止线程多次。
另外需要注意的是,如果查看取消点的POSIX要求,则几乎所有阻塞接口都必须是取消点。否则,在任何完全阻塞的线程(在这样的调用中)上,将没有安全的方法来终止该线程。

http://man7.org/linux/man-pages/man7/pthreads.7.html


1
啊,这样就说得通了。所以取消点确实是用来取消线程的,但与“阻塞点”的关系并不直接,因为正如你所说,否则你可能会遇到无法终止的“死锁”线程...我想这回答了我的问题并消除了我的困惑 :) - code_fodder
3
技术上可以使用 pthread_kill 来终止死锁线程。目标线程会收到 SIGKILL 信号。但是,例如,线程本地存储中的对象析构函数将不会被调用。此外,当被杀死时,不能保证用于该线程的内部结构将被释放。如果无法进行 join,pthread_cancel 应该是“最清洁”的方法来终止线程。 - Bogdan V.
2
@BogdanV.:如果你用SIGKILL信号打断一个进程中的任何线程,整个进程都会死亡,而不仅仅是线程。这必须这样工作,因为常规的kill系统调用已经随机选择了目标线程,pthread_kill只允许你选择要发出信号的线程。POSIX明确记录了这一点:“请注意,pthread_kill()只会在给定线程的上下文中处理信号;信号动作(终止或停止)会影响整个进程。” - Kevin

22

当你想要从另一个线程(例如主线程)使用pthread_cancel()终止或取消一个线程时,以下情况会发生(参见):

pthread_cancel()函数向线程 thread 发送取消请求。

目标线程不会立即终止,而是在达到取消点(参见)时终止:

POSIX.1规定某些函数必须成为取消点,而某些其他函数可以成为取消点。如果线程可被取消,其可取消性类型为延迟,并且线程有待处理的取消请求,则当它调用一个作为取消点的函数时,该线程被取消。

这些函数是否也可能阻塞线程的执行,在此时并不相关。文档中有这些函数的列表:

请注意,这里出于简化的原因省略了一些可能影响线程行为和“可取消性”的设置。更多阅读:

  • pthread_setcancelstate函数
  • pthread_testcancel函数

  • 谢谢提供的所有链接,我已经阅读了大部分内容。我认为我困惑的原因是我以为“阻塞点”和“取消点”是一样的,而其他答案已经为我解决了这个问题。尽管如此,感谢你提供的所有信息 :) - code_fodder

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接