1. 程式人生 > >pthread中取消線程

pthread中取消線程

HP 下一條 表示 阻塞 var col 放置 blank 調度

取消線程

取消操作允許線程請求終止其所在進程中的任何其他線程。不希望或不需要對一組相關的線程執行進一步操作時,可以選擇執行取消操作。

取消線程的一個示例是異步生成取消條件,例如,用戶請求關閉或退出正在運行的應用程序。另一個示例是完成由許多線程執行的任務。其中的某個線程可能最終完成了該任務,而其他線程還在繼續運行。由於正在運行的線程此時沒有任何用處,因此應當取消這些線程。

取消點

僅當取消操作安全時才應取消線程。pthreads 標準指定了幾個取消點,其中包括:

  • 通過 pthread_testcancel 調用以編程方式建立線程取消點。

  • 線程等待 pthread_cond_waitpthread_cond_timedwait(3C)

    中的特定條件出現。

  • sigwait(2) 阻塞的線程。

  • 一些標準的庫調用。通常,這些調用包括線程可基於其阻塞的函數。有關列表,請參見 cancellation(5) 手冊頁。

缺省情況下將啟用取消功能。有時,您可能希望應用程序禁用取消功能。如果禁用取消功能,則會導致延遲所有的取消請求,直到再次啟用取消請求。

有關禁用取消功能的信息,請參見pthread_setcancelstate 語法

放置取消點

執行取消操作存在一定的危險。大多數危險都與完全恢復不變量和釋放共享資源有關。取消線程時一定要格外小心,否則可能會使互斥保留為鎖定狀態,從而導致死鎖。或者,已取消的線程可能保留已分配的內存區域,但是系統無法識別這一部分內存,從而無法釋放它。

標準 C 庫指定了一個取消接口用於以編程方式允許或禁止取消功能。該庫定義的取消點是一組可能會執行取消操作的點。該庫還允許定義取消處理程序的範圍,以確保這些處理程序在預期的時間和位置運行。取消處理程序提供的清理服務可以將資源和狀態恢復到與起點一致的狀態。

必須對應用程序有一定的了解,才能放置取消點並執行取消處理程序。互斥肯定不是取消點,只應當在必要時使之保留盡可能短的時間。

請將異步取消區域限制在沒有外部依賴性的序列,因為外部依賴性可能會產生掛起的資源或未解決的狀態條件。在從某個備用的嵌套取消狀態返回時,一定要小心地恢復取消狀態。該接口提供便於進行恢復的功能:pthread_setcancelstate(3C)

在所引用的變量中保留當前的取消狀態,pthread_setcanceltype(3C) 以同樣的方式保留當前的取消類型。

在以下三種不同的情況下可能會執行取消操作:

  • 異步

  • 執行序列中按標準定義的各個點

  • 調用 pthread_testcancel()

缺省情況下,僅在 POSIX 標準可靠定義的點執行取消操作。

無論何時,都應註意資源和狀態恢已復到與起點一致的狀態

pthread_setcancelstate 語法

int	pthread_setcancelstate(int state, int *oldstate);
#include <pthread.h>

int oldstate;

int ret;

/* enabled */

ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);


/* disabled */

ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);

pthread_setcancelstate 返回值

pthread_setcancelstate() 在成功完成之後返回零。其他任何返回值都表示出現了錯誤。如果出現以下情況,pthread_setcancelstate() 函數將失敗並返回相應的值

EINVAL

描述:

狀態不是 PTHREAD_CANCEL_ENABLEPTHREAD_CANCEL_DISABLE

pthread_setcanceltype 語法

int	pthread_setcanceltype(int type, int *oldtype);
#include <pthread.h>

int oldtype;

int ret;

/* deferred mode */

ret = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldtype);

/* async mode*/

ret = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);

創建線程時,缺省情況下會將取消類型設置為延遲模式。在延遲模式下,只能在取消點取消線程。在異步模式下,可以在執行過程中的任意一點取消線程。因此建議不使用異步模式。

pthread_setcanceltype 返回值

pthread_setcanceltype() 在成功完成之後返回零。其他任何返回值都表示出現了錯誤。如果出現以下情況,該函數將失敗並返回對應的值。

EINVAL

描述:

類型不是 PTHREAD_CANCEL_DEFERREDPTHREAD_CANCEL_ASYNCHRONOUS

pthread_testcancel 語法

void pthread_testcancel(void);
#include <pthread.h>


pthread_testcancel(); 

當線程取消功能處於啟用狀態且取消類型設置為延遲模式時,pthread_testcancel() 函數有效。如果在取消功能處於禁用狀態下調用 pthread_testcancel(),則該函數不起作用。

請務必僅在線程取消操作安全的序列中插入 pthread_testcancel()。除通過 pthread_testcancel() 調用以編程方式建立的取消點以外,pthread 標準還指定了幾個取消點。有關更多詳細信息,請參見取消點。

pthread_testcancel 返回值

pthread_testcancel() 沒有返回值。

解釋:
有兩個線程T1,T2,都要調用fun()函數,函數內容為:fun()
{
int len;

...
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,&iOldState);
pthread_testcancel();
len=read(...);

pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,&iOldState);
...
}
pthread_setcancelstate()函數只是改變本線程(註意是本線程)的cancel state。所以T1進入fun()函數,
執行到pthread_setcancelstate()函數時,只是改變了T1本身的cancel state,並不能改變T2的cancel state。 線程執行到pthread_testcancel()函數時,並不一定會馬上取消(退出)。
描述一下取消一個線程的過程: 1) 其他線程通過調用pthread_cancel()函數,向目標線程發送取消請求(cancellation request)。 2) 取消請求發出後,根據目標線程的cancel state來決定取消請求是否會到達目標線程: a. 如果目標線程的cancel state是PTHREAD_CANCEL_ENABLE(默認),取消請求會到達目標線程。 b. 如果目標線程的cancel state是PTHREAD_CANCEL_DISABLE,取消請求會被放入隊列。直到目標線程的cancel state變為PTHREAD_CANCEL_ENABLE,取消請求才會從隊列裏取出,發到目標線程。 3) 取消請求到達目標線程後,根據目標線程的cancel type來決定線程何時取消: 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的函數的時候才會取消,它會在獲得調度之後立即取消,因為內核調度會有延時,所以並不能保證時間上的“立即”)。 舉個例子,說明一下這些與線程取消相關的函數的用法:
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的代碼 */
...
}


pthread_testcancel()函數一方面可以用來使LinuxThread與POSIX一致;另一方面就是如果線程函數裏沒有作為取消點的函數,就可以用pthread_testcancel()人為地創建取消點,使得該線程一旦收到取消請求就可以被取消。

pthread中取消線程