pthread_cancel 與解構子行為實驗
Manual
pthread_cancel(3) - Linux manual page
根據 linux manual 所寫,pthread_cancel 基本上可以在一些可中斷的地方(POSIX 給了一個清單,大概是 IO 操作的時候)中斷 thread。
這時就好奇了:C++ 的 Destructor 會不會被觸發?這並沒有寫在文件上。
Code
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
struct Obj {
Obj() {
puts("constructor");
}
~Obj() {
puts("destructor");
}
};
void* try_thread(void*) {
Obj obj;
puts("try_thread: start");
int i;
for (i = 0; i < 100; ++i) {
printf("try_thread: %d\n", i);
sleep(1);
}
puts("try_thread: end");
return 0;
}
int main() {
pthread_t t;
pthread_create(&t, NULL, try_thread, NULL);
sleep(1);
sleep(1);
pthread_cancel(t);
pthread_join(t, NULL);
puts("joined");
return 0;
}
Result
gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)
constructor
try_thread: start
try_thread: 0
try_thread: 1
destructor
joined
Apple clang version 15.0.0 (clang-1500.0.40.1)
constructor
try_thread: start
try_thread: 0
try_thread: 1
joined
glibc Code Tracing
從結果上來看,glibc 的 pthread_cancel implement 可以 trigger Destructor ?
pthread_cancel.c - nptl/pthread_cancel.c - Glibc source code (glibc-2.38.9000) - Bootlin
裡面的機制是註冊一個 signal handler,然後對要 cancel 的 thread 扔 signal ,讓特定 thread 觸發 signal handler 呼叫 __do_cancel
。
pthreadP.h - sysdeps/nptl/pthreadP.h - Glibc source code (glibc-2.38.9000) - Bootlin
/* Called when a thread reacts on a cancellation request. */
void __do_cancel () {
// ...
__pthread_unwind ((__pthread_unwind_buf_t *)
THREAD_GETMEM (self, cleanup_jmp_buf));
}
裡面呼叫 __pthread_unwind
unwind.c - nptl/unwind.c - Glibc source code (glibc-2.38.9000) - Bootlin
看起來裡面是扔 Exception?所以可以觸發 Destructor。
void __pthread_unwind (__pthread_unwind_buf_t *buf) {
struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;
struct pthread *self = THREAD_SELF;
/* This is not a catchable exception, so don't provide any details about
the exception type. We do need to initialize the field though. */
THREAD_SETMEM (self, exc.exception_class, 0);
THREAD_SETMEM (self, exc.exception_cleanup, &unwind_cleanup);
_Unwind_ForcedUnwind (&self->exc, unwind_stop, ibuf);
/* NOTREACHED */
/* We better do not get here. */
abort ();
}
Reference
pthread_cancel(3) - Linux manual page
Cancelling a thread using pthread_cancel : good practice or bad