APUE——線程取消

APUE原文
線程取消鏈接

1. 線程取消過程

先描述一下取消一個線程的過程:

  1. 其他線程通過調用pthread_cancel()函數,向目標線程發送取消請求(cancellation request)。

  2. 取消請求發出後,根據目標線程的cancel state來決定取消請求是否會到達目標線程:pthread_setcancelstate

    a. 如果目標線程的cancel state是PTHREAD_CANCEL_ENABLE(默認),取消請求會到達目標線程。
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)
    b. 如果目標線程的cancel state是PTHREAD_CANCEL_DISABLE,取消請求會被放入隊列。直到目標線程的cancel state變爲PTHREAD_CANCEL_ENABLE,取消請求才會從隊列裏取出,發到目標線程。

  3. 取消請求到達目標線程後,根據目標線程的cancel type來決定線程何時取消:pthread_setcanceltype

    a. 如果目標線程的cancel type是PTHREAD_CANCEL_DEFERRED(默認),目標線程並不會馬上取消,而是在執行下一條cancellation point的時候纔會取消。有很多系統函數都是cancellation point,詳細的列表可以在Linux上用man 7 pthreads查看。除了列出來的cancellation point,pthread_testcancel()也是一個cancellation point。就是說目標線程執行到pthread_testcancel()函數的時候,如果該線程收到過取消請求,而且它的cancel type是PTHREAD_CANCEL_DEFERRED,那麼這個線程就會在這個函數裏取消(退出),這個函數就不再返回了,目標線程也沒有了。

    b. 如果目標線程的cancel type是PTHREAD_CANCEL_ASYNCHRONOUS,目標線程會立即取消(這裏的“立即”只是說目標線程不用等執行到屬於cancellation point的函數的時候纔會取消,它會在獲得調度之後立即取消,因爲內核調度會有延時,所以並不能保證時間上的“立即”)。

2.線程取消函數

#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
返回值:若成功則返回0,否則返回錯誤編號

pthread_setcancelstate把當前的可取消狀態設置爲state,把原來的可取消狀態存放在由oldstate指向的內存單元中,這兩步是原子操作。
當狀態設置爲PTHREAD_CANCEL_DISABLE之後,如果收到cancel,則進入未決狀態,進入隊列,當取消狀態再次變爲PTHREAD_CANCEL_ENABLE時,線程將在下一個取消點上對所有未決的取消請求進行處理。

在這裏插入圖片描述
在這裏插入圖片描述

#include <pthread.h>
void pthread_testcancel(void);
  1. 當pthread_testcancel調用,且線程中有未決的請求,且狀態爲PTHREAD_CANCEL_DISABLE,則沒有作用
  2. 當pthread_testcancel調用,且線程中有未決的請求,且狀態爲PTHREAD_CANCEL_ENABLE,則線程取消,如果是異步取消,則當即取消,如果是延遲取消,則等待等待點再取消!
#include <pthread.h>
int pthread_setcanceltype(int type, int *oldtype);
返回值:若成功則返回0,否則返回錯誤編號

type參數可以是PTHREAD_CANCEL_DEFERRED,也可以是PTHREAD_CANCEL_ASYNCHRONOUS,pthread_setcanceltype函數把取消類型設置爲type,把原來的取消類型返回到oldtype指向的整數單元。

3. 代碼分析

void thread_function(void *arg)
{
/**
* 線程準備執行一些關鍵工作,在這個過程中不希望被取消。
* 所以先通過pthread_setcancelstate()將本線程的cancel state
* 設爲disabled。
*/
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
/* 執行關鍵工作 */
...
/**
* 關鍵工作執行完成,可以被取消。
* 通過pthread_setcancelstate()將本線程的cancel state
* 設爲enabled。
*/
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
/**
* 調用pthread_testcancel()函數,檢查一下在cancel state
* 爲disabled狀態的時候,是否有取消請求發送給本線程。
* 如果有的話就取消(退出)。
*/
pthread_testcancel();
/**
* pthread_testcancel()返回了,表明之前沒有取消請求發送給本線程,
* 繼續其餘的工作。
* 這時候如果有取消請求發送給本線程,會在下一次執行到
* cancellation point的時候(例如sleep(), read(), write(), ...)時取消。
*/
...
/**
* 從這裏開始,函數裏不再包含cancellation point了。
* 如果收到取消請求,將無法取消。所以先把本線程的cancel type
* 設爲asynchronous,收到取消請求將立即取消。
*/
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
/* 不包含cancellation point的代碼 */
...
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章