pthread_cancel函數注意事項

/**************************************************
相關函數:
     #include <pthread.h>
     int pthread_cancel(pthread_t thread)
                     成功返回0,失敗返回錯誤碼
**************************************************/

此函數是POSIX提供的用於取消同一進程中的其它線程,此函
數只發送取消請求,並不等待要取消的進程退出!線程可以
選擇忽略或是選擇其它動作!

需要注意的是:
當我們調用它取消一個已經獲得互斥鎖/匿名信號量/寫鎖....但
還未釋放其所獲得鎖的線程時,如果此線程被取消,此後所有想
要獲得此時執行任務的線程都將處於睡眠狀態,直到此鎖被釋放.
爲避免此問題的產生,我們可以調用一組函數:
/**************************************************
    #include <pthread.h>

    void pthread_cleanup_push(void (*routine)(void *), void *arg)
    void pthread_cleanup_pop(int execute)
        參數解釋:routine爲函數指針,arg爲傳遞給routine的參數
        execute爲零時,從棧中刪除註冊的函數,刪除後將再也
        不被執行。
**************************************************/
這兩個函數被稱爲線程清理處理程序,類似於atexit函數,我們
可以註冊多個清理函數,當執行以下動作時我們所註冊的函數將會
回調(執行順序與註冊順序相反):
    1.線程從pthread_exit(void *)函數退出時。
    2.線程響應取消請求時。
    3.執行pthread_cleanup_pop函數,execute參數爲非零時。

這兩個線程清理處理程序必須成對出現,必須處於同一作用域中,
否則會編譯出錯。
實例:
    如何使用這些函數處理以上問題!
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <signal.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <pthread.h>

pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;

void *count(void *arg)
{
    int i=1;
    while(1)
    {
        sleep(1);
        printf("sec: %d\n", i++);
    }
}

void handler(void *arg)
{
    printf("[%u] is cancelled.\n", (unsigned)pthread_self());
    pthread_mutex_t *pm = (pthread_mutex_t *)arg;

    pthread_mutex_unlock(pm);
}

void *routine(void *arg)
{
    #ifdef CLEANUP
    pthread_cleanup_push(handler, (void *)&m);
    #endif

    pthread_mutex_lock(&m);
    printf("[%u] lock the mutex!\n", (unsigned)pthread_self());

    /*
    ** During sleep(), if the calling thread received a cancel-
    ** request and HASN'T established any cleanup handlers to
    ** unlock the mutex, it will leave the mutex a DEAD-LOCK
    ** state.
    */
    sleep(2);
    printf("[%u]: job finished!\n", (unsigned)pthread_self());


    pthread_mutex_unlock(&m);
    printf("[%u] unlock the mutex!\n", (unsigned)pthread_self());

    /*
    ** NOTE: 
    **
    ** pthread_cleanup_push() and pthread_cleanup_pop() may be
    ** implemented as macro that expand to text containing '{'
    ** and '}', respectively. For this reason, the caller must
    ** user them pairly and ensure that they are paired within
    ** a same function and at the same lexical nesting level.
    */
    #ifdef CLEANUP
    pthread_cleanup_pop(0);
    #endif


    pthread_exit(NULL);
}

int main(int argc, char **argv)
{
    pthread_t t, t1, t2;
    pthread_create(&t, NULL, count, NULL);


    pthread_create(&t1, NULL, routine, NULL);
    pthread_create(&t2, NULL, routine, NULL);
    printf("[%u] ==> t1\n", (unsigned)t1);
    printf("[%u] ==> t2\n", (unsigned)t2);
    printf("[%u] ==> main\n", (unsigned)pthread_self());

    sleep(1);
    pthread_cancel(t1);
    pthread_cancel(t2);

    sleep(2);

    pthread_mutex_lock(&m);
    printf("[%u] locked the mutex!\n",
        (unsigned)pthread_self());
    pthread_mutex_unlock(&m);

    exit(0);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章