1. POSIX 线程取消点、清理处理器与线程局部存储析构函数的执行顺序是什么?
POSIX 线程取消点、清理处理器与线程局部存储析构函数的执行顺序是什么?取消语义有哪些关键点?
- 取消点(cancellation point):pthread_cancel 后线程在阻塞调用处被取消
- 清理处理器(cleanup handlers):pthread_cleanup_push/pop,在取消时逆序执行
- TLS 析构与进程退出路径上的顺序:取消→清理→TLS 析构
取消语义分两步:pthread_cancel 发送取消请求(默认 PTHREAD_CANCEL_DEFERRED 延迟取消),目标线程只有在到达"取消点"(阻塞的系统调用如 read/write/cond_wait/join,或 pthread_testcancel 显式点)时才被取消;到达取消点时,线程按 LIFO 顺序执行所有已注册的清理处理器(pthread_cleanup_push 注册、pthread_cleanup_pop(0) 延迟弹出,取消时自动弹出执行),之后线程终止——终止发生在"取消点调用返回之前"(调用本身返回未完成状态)。若线程设置 PTHREAD_CANCEL_ASYNCHRONOUS(异步取消),则可在任意指令处取消(不推荐:可能破坏内部状态)。线程退出(正常返回或 pthread_exit)时同样执行清理处理器,因此清理处理器是"无论正常/取消退出都释放资源(锁、内存、fd)"的保证机制。
顺序细节:取消时执行顺序为"清理处理器(LIFO,pthread_cleanup_push 逆序)→ 线程结束";若线程还注册了 TLS 析构(pthread_key 的 destructor),它们在线程结束路径上按"未设置键值的顺序、最多 PTHREAD_DESTRUCTOR_ITERATIONS 次"执行——整体顺序是:取消点处执行清理处理器,然后 TLS 析构运行,最后线程终止(TLS 析构与清理处理器互不交错:先清理后析构)。进程级退出(exit)只运行 atexit;pthread_exit 不运行 atexit 但运行清理处理器与 TLS 析构。工程要点:持锁区域必须 push 清理处理器(取消时解锁),否则死锁;取消点处的阻塞调用返回 EINTR/EAGAIN 需判断是否被取消(pthread_cancel 后若阻塞调用被信号打断且清理已执行,线程已亡)。可取消状态与类型可用 pthread_setcancelstate/setcanceltype 控制。
以"延迟取消→取消点→清理处理器 LIFO→TLS 析构→终止"的顺序链回答,再强调清理处理器在正常/取消两条退出路径的一致性作用。