pthread_cancel

C++ interacts with thread cancellation like this:
1. Does destructors run? (They MUST to avoid resource leaks)
2. Do we map thread cancellation to an exception? (On the one hand you don't want to duplicate the code in exception handlers and in functions registered with pthread_cleanup_push(). On the other hand you can't have a thread catch the thread cancellation exception and not terminate.)

The Linux POSIX threads implementation (NPTL in Glibc) actually behaves very well, see:
http://udrepper.livejournal.com/21541.html
"abi::__forced_unwind" is the special exception caused by thread cancellation that must be rethrown.

The problem is that the above is not standardized in POSIX 2008 or C++ 2011. For example,C++11 threads don't have cancellation support:
http://www2.research.att.com/~bs/C++0xFAQ.html#std-threads

There are important pthread implementations that don't support C++ thread cancellation well:
1. Apple OSX, iOS
2. Google Android
3. QNX

I recommend against using thread cancellation in general since "cancellation points" is easy to get wrong.

References:
1. The conceptual problems with C++ and thread cancellation is explained well here:
http://cygwin.com/ml/pthreads-win32/1999/msg00134.html

2. Solaris runs C++ destructors on thread cancellation:
http://download.oracle.com/docs/cd/E18659_01/html/821-1383/bkaid.html

3.One good use case for an exception like Glibc's abi::__force_unwind: a user of boost::python may want to catch the C++ cancellation, throw an equivalent Python exception, and rethrow the C++ exception at the other end.

因為 pthread_cancel() 只是『要求』該 thread 終止,目標 thread 何時回應與 pthread_cancel() 的回傳之間是 asynchronous 的。

一個相關的觀念是 PTHREAD_CANCEL_ASYNCHRONOUS:
若你將 sleepyThread() 改成 calcThread() 並在該 thread 中完全不發 syscall 只進行 CPU 運算,例如在無窮迴圈內算 Fibnacci series 且不要印出來,則該 thread 是不會結束的。

除非你在 calcThread() 一開頭加上:
pthread_setcanceltype(PTHREAD_CANCEL_SYNCHRONOUS, &old);
詳見:
http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html#tag_02_09_05

另外,
1. 你的 sample code 中有 "id=pthread_create(…)" 但 pthread_create() 傳回的是 error code

2. 你說:"如果看pthread_cancel這個function可以知道底層他其實指找出thread id並且送給他signal" 但其實 glibc 程式碼跟註解是寫說只有對特別設成 PTHREAD_CANCEL_ASYNCHRONOUS 的 thread 才送 SIGCANCEL.

為了加速,對預設的 thread 只是在變數中紀錄『該 thread 已經被 cancel 了』而已,見 "CANCEL_ENABLED_AND_CANCELED_AND_ASYNCHRONOUS":
http://sourceware.org/git/?p=glibc.git;a=blob;f=nptl/pthread_cancel.c;h=55bb0da922ba1ed1c4bd33478075e1b41f2baaff;hb=HEAD

"在C++如果有cancel thread這種需求要怎麼辦?"

另外一個常見解法,我猜可能不用講,就是『修改架構』以避免產生 thread cancellation 需求:
1. 讓想 cancel 的 thread 有一個跟別的 thread 溝通用的 request queue 或 main loop (我猜你 code base 中一定有)

2. 確保想 cancel 的 thread 不會 block 在 request queue 以外的 I/O 上。例如若原本會 block 在某個 TCP connection 上,改成用 select / poll / epoll 為基礎的 main loop 與 O_NONBLOCK.

第二點 async I/O 的改法跟你原本 thread 用的 request queue / main loop 的寫法有關,若你原本用的 request queue 底層就是用 select / poll / epoll 實作的,可以同時支援 async I/O 與自己定義的"請你 cancel 吧" request 當然最好:
http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#code_ev_async_code_how_to_wake_up_an

http://think-async.com/Asio/boost_asio_1_4_8/doc/html/boost_asio/reference/io_service/post.html

但很多時候你 code base 中原本可能有個用 semaphore 或 conditional variable 實作的 request queue。此時你可以產生一個新的 async I/O thread,在該 thread 中跑一個 select / poll / epoll based 的 main loop 與 async I/O,並跟你想 cancel 的 thread 傳遞 I/O request.

ex: async I/O thread 透過 epoll() 同時監控多個 TCP connection, 發現其中一個可以讀了,用 recv() 讀出並將資料傳進原本想 cancel 的 thread 的 request queue 中。

3. 想 cancel thread 時,傳自己定義的"請你 cancel 吧" request 給目標 thread 的 request queue.
能夠直接 request 某個 callback 在該 thread 中被呼叫當然也可。當然這樣減少了 cancellation points.

上面舉出的 libev 與 boost::asio 都算是好用的 main loop.

Reference:
https://plus.google.com/102249536116095884743/posts/EtAyuiKq6H4

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License