歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

pthread_cancel用法及常見問題

先看下面一段程序:
[cpp]
view plaincopy
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
void* func(void *)
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); //允許退出線程
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); //設置立即取消
while (1)
{
;
}
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t thrd;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if ( pthread_create(&thrd, &attr, func, NULL) )
{
perror( "pthread_create error ");
exit(EXIT_FAILURE);
}
if ( !pthread_cancel(thrd) )
{
printf( "pthread_cancel OK\n " );
}
sleep( 10 );
return 0;
}
上面程序並不會將子線程取消,why?
這是因為子線程一直在while()循環,沒有掛起,所以不能將其取消;那麼該如何才能取消呢?
先來看一下pthread_cancel()的用法:
線程取消的方法是向目標線程發Cancel信號,但如何處理Cancel信號則由目標線程自己決定,或者忽略、或者立即終止、或者繼續運行至Cancelation-point(取消點),由不同的Cancelation狀態決定。
線程接收到CANCEL信號的缺省處理(即pthread_create()創建線程的缺省狀態)是繼續運行至取消點,也就是說設置一個CANCELED狀態,線程繼續運行,只有運行至Cancelation-point的時候才會退出。
(1)什麼是線程取消點
根據POSIX標准,pthread_join()、pthread_testcancel()、pthread_cond_wait()、pthread_cond_timedwait()、sem_wait()、sigwait()等函數以及read()、write()等會引起阻塞的系統調用都是Cancelation-point,而其他pthread函數都不會引起Cancelation動作。但是pthread_cancel的手冊頁聲稱,由於LinuxThread庫與C庫結合得不好,因而目前C庫函數都不是Cancelation-point;但CANCEL信號會使線程從阻塞的系統調用中退出,並置EINTR錯誤碼,因此可以在需要作為Cancelation-point的系統調用前後調用pthread_testcancel(),從而達到POSIX標准所要求的目標,即如下代碼段:
pthread_testcancel();
retcode = read(fd, buffer, length);
pthread_testcancel();
(2)程序設計方面的考慮
如果線程處於無限循環中,且循環體內沒有執行至取消點的必然路徑,則線程無法由外部其他線程的取消請求而終止。因此在這樣的循環體的必經路徑上應該加入pthread_testcancel()調用。
(3)與線程取消相關的pthread函數
int pthread_cancel(pthread_t thread)
發送終止信號給thread線程,如果成功則返回0,否則為非0值。發送成功並不意味著thread會終止。
int pthread_setcancelstate(int state, int *oldstate)
設置本線程對Cancel信號的反應,state有兩種值:PTHREAD_CANCEL_ENABLE(缺省)和PTHREAD_CANCEL_DISABLE,分別表示收到信號後設為CANCLED狀態和忽略CANCEL信號繼續運行;old_state如果不為NULL則存入原來的Cancel狀態以便恢復。
int pthread_setcanceltype(int type, int *oldtype)
設置本線程取消動作的執行時機,type由兩種取值:PTHREAD_CANCEL_DEFFERED和PTHREAD_CANCEL_ASYCHRONOUS,僅當Cancel狀態為Enable時有效,分別表示收到信號後繼續運行至下一個取消點再退出和立即執行取消動作(退出);oldtype如果不為NULL則存入運來的取消動作類型值。
void pthread_testcancel(void)
檢查本線程是否處於Canceld狀態,如果是,則進行取消動作,否則直接返回
按照以上的描述是不是說在linux下,pthread_join()、pthread_testcancel()、pthread_cond_wait()、pthread_cond_timedwait()、sem_wait()、sigwait()等函數以及read()、write()等會引起阻塞的系統調用在linux下並不是取消點啊?我不明白為什麼可以在需要作為Cancelation-point的系統調用前後調用pthread_testcancel(),就可以達到POSIX標准所要求的目標,我還是不太理解取消點的內涵,
pthread_testcancel();
retcode = read(fd, buffer, length);
pthread_testcancel();
加兩個pthread_testcancel(); 是干什麼的?特別是最後一個pthread_testcancel();按照上面的描述是不是線程運行到retcode = read(fd, buffer, length); 線程就終止了?那還要最後一個pthread_testcancel();做什麼啊?
另外,查閱裡相關資料,有人這樣說:
首先,取消點並不是為了取消而存在的(pthread_testcancel除外),它們是等待其他信號的,比如pthread_cond_wait是等待某個條件的,sem_wait等待一個信號量。它們的共同點是“引起阻塞的系統調用”,在阻塞以後,除了等待的特定信號以外還可以處理一些公共信號,比如CANCEL信號。接收到特定信號後將恢復線程,而接收到CANCEL信號將退出線程(我理解為一個條件return)。
Read和Write在POSIX中是標准的取消點,因為它們也進行了“引起阻塞的系統調用”,但是因為Linux自身的問題,沒有在這些函數中實現取消點,所以才需要添加pthread_testcancel來完成POSIX標准。按照你貼出的文字,C庫函數都沒有實現取消點,其他的pthread_開頭的和wait結尾的應該都是實現了的。
至於後面也加pthread_testcancel,可能是進入和退出系統調用是兩個獨立的取消點吧,應對於I/O操作開始後但還未結束時的CANSEL信號,也許只是因為I/O比較費時間所以測試兩次:)
Copyright © Linux教程網 All Rights Reserved