歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

POSIX線程的創建和取消

先看一個例子:pthread1.c

  1. #if defined(WIN32)
  2.     #include <windows.h>  // void Sleep(DWORD ms)   
  3.     #define SLEEP(ms) Sleep(ms)   
  4. #else if defined(LINUX)   
  5.     #include <unistd.h>   // unsigned int sleep(unsigned int)   
  6.     #include <stdio.h>   
  7.     #include <stdlib.h>   
  8.     #define SLEEP(ms) sleep(ms)   
  9. #endif   
  10.   
  11. #include <pthread.h>   
  12.   
  13. /** 作為線程入口的函數 */  
  14. void * print_message_function(void *ptr)  
  15. {  
  16.     SLEEP(5);  
  17.     char *message;  
  18.     message = (char *) ptr;  
  19.     printf("%s \n", message);  
  20.     return NULL;  
  21. }  
  22.   
  23. int main(int argc, char* argv[])  
  24. {  
  25.     pthread_t thread1, thread2;  
  26.     char *message1 = "Thread 1";  
  27.     char *message2 = "Thread 2";  
  28.     int  iret1, iret2;  
  29.   
  30.     // 成功創建線程時返回零   
  31.     iret1 = pthread_create(&thread1, NULL, &print_message_function, (void*) message1);  
  32.     iret2 = pthread_create(&thread2, NULL, &print_message_function, (void*) message2);  
  33.   
  34.     /* 等待兩個線程結束 -- 同步 
  35.      * 如果不同步,則有可能主線程的return先執行,導致子線程未完成任務而先完蛋 
  36.      * 可以啟用Sleep試試。 
  37.      */  
  38.     pthread_join(thread1, NULL);  
  39.     pthread_join(thread2, NULL);  
  40.   
  41.     printf("Thread 1 returns: %d\n", iret1);  
  42.     printf("Thread 2 returns: %d\n", iret2);  
  43.       
  44.     return 0;  
  45. }  
  •  在Linux下編譯:
    * C compiler: cc -lpthread pthread1.c
    * C++ compiler: g++ -lpthread pthread1.c

  • 結束線程的方法:
    * pthread_exit
    * 讓函數自己返回
    * exit 停止整個進程(當然包括所有的線程)

  • 創建線程的函數原型:
  1. int pthread_create(pthread_t * thread,  
  2.                    const pthread_attr_t * attr,  
  3.                    void* (*start_routine)(void*),  
  4.                    void *arg);  

  •  pthread_create 的第二個參數pthread_attr_t

    struct pthread_attr_t
    {
        enum    新線程是否與進程中其它線程脫離同步
        {
            PTHREAD_CREATE_JOINABLE    [default]   可以在創建後用 pthread_detach 脫離同步
            PTHREAD_CREATE_DETACHED                  不能用 pthread_join 來同步,退出時自行釋放資源
        } __detachstate;
    
        enum    新線程的調用策略
        {
            SCHED_OTHER [default]    非實時
            SCHED_RR                           實時,輪轉法    - 僅對超級用戶有效
            SCHED_FIFO                        實時,先入先出    - 僅對超級用戶有效
        } __schedpolicy;
    
        struct sched_param        在運行時用 pthread_setschedparam 更新。
        {
            int sched_priority    線程的運行優先級。當上面的 __schedpolicy 為“實時”時才有效。缺省是零。
        } __schedparam;
    
        enum
        {
            PTHREAD_EXPLICIT_SCHED [default]    顯式指定調度策略和調度參數,即使用 attr 中的值
            PTHREAD_INHERIT_SCHED                     繼承調用者線程的值
        } __inheritsched;
    
        enum    線程間競���CPU的范圍
        {
            PTHREAD_SCOPE_SYSTEM [default]   目前Linux只實現了這一種
            PTHREAD_SCOPE_PROCESS              僅與同進程的線程競爭
        } __scope;
    }

    下面三個沒用過
    * guard size
    * stack address (See unistd.h and bits/posix_opt.h _POSIX_THREAD_ATTR_STACKADDR)
    * stack size (default minimum PTHREAD_STACK_SIZE set in pthread.h)

  •  創建線程時,如果寫成下面的樣子,也是可以的。這屬於精簡模式,作為函數指針的傳入參數是和上面等價的:
iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1);

  •  等待其它線程停止
int pthread_join(pthread_t th, void **thread_return);
    * th - 調用線程變為掛起狀態,等待線程退出。退出線程可用 pthread_exit() 或者 cancel 類線程函數。
    * thread_return - 不置為NULL的話,可以傳出返回值。

  •  退出當前線程
void pthread_exit(void *retval);
若要在退出時返回數據在retval指向的內存裡,務必保證該內存不是在線程局部空間裡,否則會隨著線程退出而消失。

  •  可以通過向某線程發送cancel請求而強制終止該線程。
該線程置自己為"cancel"狀態後,運行至取消點(cancelation point),才會退出。
POSIX標准規定的取消點:
- pthread_join()、pthread_testcancel()、pthread_cond_wait()、pthread_cond_timedwait()、sem_wait()、sigwait()
- read、write等會引起阻塞的系統調用

但pthread_cancel的手冊頁聲稱,由於LinuxThread庫與C庫結合得不好,因而目前C庫函數都不是取消點。
不過,cancel信號會使線程從阻塞的系統調用中退出,並置EINTR錯誤碼。所以可以把這樣的系統調用作為取消點:

pthread_testcancel();
retcode = read(fd, buffer, length);
pthread_testcancel();

這樣,可達到POSIX的要求。

  • 與取消線程相關的函數

- int pthread_cancel (pthread_t th)    發送取消信號給線程。若成功返回零;失敗則非零。發送成功並不意味著線程會終止。

- int pthread_setcancelstate (int state, int *oldstate)    設置本線程對cancel信號的反應。
enum
{
    PTHREAD_CANCEL_ENABLE [default]   收到信號後置自己為取消狀態
    PTHREAD_CANCEL_DISABLE                 忽略cancel信號,繼續運行
} state

- int pthread_setcanceltype (int type int *oldtype)
enum
{
    PTHREAD_CANCEL_DEFERRED [default]        收到cancel信號後繼續運行,到達取消點時退出
    PTHREAD_CANCEL_ASYNCHRONOUS           立即退出
} type    當上面的state為 PTHREAD_CANCEL_ENABLE 時該變量才有效。

- void pthread_testcancel (void)

檢查本線程是否處於取消狀態,若是,立刻退出。

  1. #ifdef WIN32   
  2.     #include <windows.h>   
  3.     #define SLEEP(ms) Sleep(ms)   
  4. #else if defined(LINUX)   
  5.     #include <stdio.h>   
  6.     #define SLEEP(ms) sleep(ms)   
  7. #endif   
  8.   
  9. #include <cassert>   
  10. #include <pthread.h>   
  11.   
  12. static int s_nThreadResult = 0;  
  13.   
  14. void * theThread(void * param)  
  15. {  
  16.     int count = 0;  
  17.     while (count < 20)  
  18.     {  
  19.         printf("[Child] looping\n");  
  20.         pthread_testcancel();  
  21.         SLEEP(1);  
  22.         count ++;  
  23.     }  
  24.   
  25.     s_nThreadResult = 1;  
  26.     pthread_exit(&s_nThreadResult);  
  27.   
  28.     return NULL;  
  29. }  
  30.   
  31. int main(int argc, char * argv[])  
  32. {  
  33.     int rc = 0;  
  34.     pthread_t tid;  
  35.     rc = pthread_create(&tid, NULL, &theThread, NULL);  
  36.     assert(rc == 0 && "pthread_create");  
  37.   
  38.     SLEEP(3);  
  39.     // 若啟用下面代碼,則子線程提前返回   
  40.     //rc = pthread_cancel(tid);   
  41.     assert(rc == 0 && "pthread_cancel");  
  42.   
  43.     // 阻塞自己,等待子線程返回   
  44.     void * status = NULL;  
  45.     rc = pthread_join(tid, &status);  
  46.     assert(rc == 0 && "pthread_join", rc);  
  47.   
  48.     // 若子線程是被取消從而結束的,則無返回值   
  49.     if (status != PTHREAD_CANCELED && status != NULL)  
  50.     {  
  51.         printf("Returned value from thread: %d\n", *(int *)status);  
  52.     }  
  53.   
  54.     return 0;  
  55. }  
Copyright © Linux教程網 All Rights Reserved