POSIX线程中的线程取消

3
我正在使用POSIX线程。我的问题是,一个线程是否可以通过在pthread_cancel函数中传递自己的线程ID来取消自己?如果是,那么会有什么影响?
另外,如果一个主程序创建了两个线程,其中一个线程取消了另一个线程,那么被取消的线程的返回值和资源会发生什么变化?如何从主程序中知道哪个线程被取消了?因为主程序没有取消任何线程。
我正在使用异步取消。请帮忙解答。

我不太确定我的理解是否正确。为什么一个线程想要取消自己,而不是只是pthread_exit自己? - Martin James
3个回答

7

Q1: 是的,一个线程可以取消自己。然而,这样做会有取消操作一般带来的所有负面后果;你可能想使用 pthread_exit,它更加可预测。

Q2: 当线程被取消时,它无法生成返回值;相反,pthread_join 会将特殊值 PTHREAD_CANCELED 放入其 retval 参数所指向的位置。不幸的是,在调用 pthread_join 之前,你必须通过其他方式知道某个特定线程已经以某种方式终止,否则调用线程将永远阻塞。没有可移植的等价于 waitpid(..., WNOHANG)waitpid(-1, ...)。(手册上说“如果您认为需要此功能,则可能需要重新考虑应用程序设计”,这让我想打某个人的脸。)

Q2a: 这取决于你所说的“线程资源”。线程控制块和堆栈将被释放。所有在线程上注册的析构函数(使用pthread_cleanup_pushpthread_key_create)将被执行;一些运行时还会执行堆栈上对象的 C++ 类析构函数。应用程序员有责任确保线程拥有的所有资源都由这些机制之一覆盖。请注意,其中一些机制具有固有的竞争条件;例如,不可能打开一个文件并推送一个关闭它的清理作为原子操作,因此存在取消泄漏打开文件的窗口期。(不要认为这可以通过在打开文件之前推送清理来解决,因为 deferred 取消的常见实现是在系统调用 返回 时检查它们,即恰好定时命中操作系统将文件描述符号写入返回值寄存器和调用函数将该寄存器复制到清理期望它在的内存位置之间的微小间隙。)

Qi: 你没有问这个问题,但你应该知道,启用异步取消功能的线程正式不允许做除纯计算以外的任何事情。如果调用了 任何库函数(除了 pthread_cancelpthread_setcanceltype(PTHREAD_CANCEL_DEFERRED)pthread_setcancelstate(PTHREAD_CANCEL_DISABLE)),其行为是未定义的。


1

问题1:是的,线程可以自我取消。

问题2:如果一个线程取消了另一个线程,则其资源将一直挂起,直到主线程使用pthread_join()函数加入该线程(如果该线程是可加入的)。如果已取消的线程没有在主线程中加入,则在程序结束/终止时,资源将被释放。

问题3:我不确定,但主程序不知道哪个线程被取消了。


0

线程可以取消任何其他线程(在同一进程中),包括自身

线程通常没有返回值(它们只能有返回状态),线程的资源将在取消时释放

主程序可以存储线程的处理程序并测试其是否有效


线程确实有返回值。当线程被取消时,pthread_join将在其retval参数所指向的位置放置特殊值PTHREAD_CANCELED。请注意,这个值并不是线程的实际返回值,而是表示该线程已被取消。 - zwol
@Zack 同意,但它实际上不是返回值,而是退出状态,当然有时你可以将其用作返回值。 - Iłya Bursov
在正常情况下,放置在该位置的值是线程启动过程的返回值,因此我认为将其描述为返回值是合理的。 - zwol
另外,它不是一个整数返回状态,而是一个 void * - zwol
@Zack 你是对的,但我真的不建议使用除整数以外的任何东西。 - Iłya Bursov

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