POSIX多線程——基本線程管理函數介紹

POSIX基本的幾個線程管理函數見下表:
------------------------------------------------------------------------------------------
                     POSIX函數                                                         描述
-------------------------------------------------------------------------------------------
                    pthread_create                                   創建一個線程
                    pthread_self                                       找出自己的線程ID
                    pthread_equal                                    測試2個線程ID是否相等
                    pthread_detach                                  設置線程以釋放資源
                    pthread_join                                        等待一個線程
                    pthread_cancel                                   終止另一個線程
                    pthread_exit                                        退出線程,而不退出進程
                    pthread_kill                                         向線程發送一個信號
-------------------------------------------------------------------------------------------
 
(1)線程ID、獲取和比較
POSIX線程由一個pthread_t類型的ID來引用。線程可以通過調用pthread_self ()函數獲得自己的線程ID,這裏沒有對pthread_self 定義錯誤。
 
==========================
概要:
#include <pthread.h>                     
pthread_t   pthread_self (void);   
==========================
 
由於pthread_t  可能是一個結構,所以不能由==來直接進行比較。這裏可以使用函數pthread_equal()來比較線程ID是否相等,這裏沒有對pthread_equal定錯誤,如果兩個線程ID相等,返回非0值,否則返回0.
 
============================================
概要:
#include <pthread.h>                     
int   pthread_equal(pthread_t  t1, pthread_t  t2 );   
============================================
 
(2)創建線程
可以使用pthread_create()創建一個線程。POSIX的pthread_create()創建的線程是可以直接運行的,而不需要一個單獨的啓動操作。
 
==========================================
概要:
#include <pthread.h>
int pthread_create(pthread_t *restrict thread,
                   const pthread_attr_t *restrict attr,
                   void *(*start_routine)(void *),
                   void *restrict arg);
==========================================
在上述函數中,thread指向新創建的線程ID;參數attr表示一個封裝了線程各種屬性的屬性對象(比如棧大小、調度等信息,後面會專門介紹),如果attr爲NULL,則使用默認屬性進行創建;第三個參數start_routine是線程開始執行時調用的函數名字;第四個參數arg指針指向的數據是start_routine的參數。如果成功,函數返回0,否則返回非零錯誤碼。
 
下面例子中的代碼就是連續創建10個線程,線程中執行的代碼僅爲打印自己的線程ID,和所屬進程ID:
 
#include <pthread.h>
#include <stdio.h>
 
void *print_thread(int *i)
{
 fprintf(stderr,"number:%d,pid:%d,tid:%lld.\n",*i,getpid(),(long long)pthread_self());
      return NULL;
}
 
int main(int argc, char* argv[ ] )
{
 pthread_t tids[10];
 int i;
 for(i=0;i<10;i++)
 {
  if(pthread_create(&tids[i],NULL,print_thread,&i)==-1)
  {
   fprintf(stderr,"\nERROR: fail to creat thread.");
   tids[i]= pthread_self();
  }
 }
 return 0;
}
執行結果:
gaolu@gaolu-desktop:~$ ./thr
number:0,pid:5579,tid:3085089680.
number:1,pid:5579,tid:3076696976.
number:2,pid:5579,tid:3068304272.
number:3,pid:5579,tid:3059911568.
number:4,pid:5579,tid:3051518864.
number:5,pid:5579,tid:3043126160.
number:6,pid:5579,tid:3034733456.
number:7,pid:5579,tid:3026340752.
number:8,pid:5579,tid:3017948048.
number:9,pid:5579,tid:3009555344.
gaolu@gaolu-desktop:~$
 
(3)線程的分離(detach)和連接(join)
一般情況下,線程在退出時,是不會釋放它的資源的;
 
如果將線程分離,即創建線程以後調用pthread_detach(tid)或者線程自身調用pthread_detach(pthread_self())都可以,它設置線程的內部選項來說明,線程退出以後存儲空間可以被重新收回,分離線程退出時不會報告他們的狀態。
 
如果線程沒有分離,那麼它是可以接合(join)的,pthread_join和進程級別的函數wait_pid非常類似,該函數將調用線程掛起,直到第一個參數指定的目標線程終止爲止。如果創建線程對子線程調用了pthread_join(), 子線程退出以後,資源在進程退出以後被回收。參數value_ptr爲指向返回值的指針,這個返回值是目標線程return 或者傳遞給pthread_exit()的。
 
爲了防止內存泄漏,長時間運行的線程最終應該爲每個線程調用pthread_join() 或者pthread_detach()。
 
===========================================
概要:
#include <pthread.h>
int pthread_join(pthread_t th, void **value_ptr )
int pthread_detach(pthread_t thread )
===========================================
 
下面一個示例程序演示了pthread_detach和pthread_join之間的關係。
 
(1)子線程將自己detach了,這種情況下線程是不能被join的。
#include <pthread.h>
#include <stdio.h>
void *print_thread(void *ptr)
{
 if(pthread_detach(pthread_self())==0)
 {
      fprintf(stderr,"tid:%lld,I have detached myself successfully.\n",(long long)pthread_self( ) );
 }
 else
 {
      fprintf(stderr,"\nERROR:detach failed.");
 }
      return NULL;
}
int main(int argc, char* argv[])
{
 pthread_t tid;
 int *exitcode;
 if(pthread_create(&tid,NULL,print_thread,NULL)==-1)
 {
      fprintf(stderr,"\nERROR: fail to creat thread.");
 }
 fprintf(stderr,"my pid is %d.\n",getpid());
 if(pthread_join(tid,&exitcode)!=0)
 {
      fprintf(stderr,"ERROR: fail to join thread.\n");
 }
 else
 {
      fprintf(stderr,"parent end successfully.\n");
 }
 
 return 0;
}
gaolu@gaolu-desktop:~$ ./thr
tid:3084360592,I have detached myself successfully.
my pid is 5652.
ERROR: fail to join thread.
gaolu@gaolu-desktop:~$
 
(2)修改創建的線程只是做了普通的打印信息,join可以執行成功。
void *print_thread(void *ptr)
{
     fprintf(stderr,"My tid:%lld.\n",(long long)pthread_self());
}
gaolu@gaolu-desktop:~$ ./thr
My tid:3085216656.
my pid is 5702.
parent end successfully.
gaolu@gaolu-desktop:~$
(4)線程退出和取消
線程return一個指針value_ptr的相當於隱式地調用了pthread_exit(value_ptr)函數。如果進程的最後一個線程調用了pthread_exit,進程就會帶着狀態返回值0退出。
 
對於一個被join了的線程來說,其返回值vlaue_ptr是可用的。也就是說value_ptr一定是要指向線程結束以後還存在的數據------這個問題可以通過幾種方式解決:比如創建線程給被創建的線程傳遞參數時,參數中傳遞一個指針,作爲被創建線程的返回值,這樣返回值是位於創建線程的棧上;另外在被創建線程malloc內存,將指針作爲返回值使用也可以。
 
另外,線程可以通過取消機制迫使其他線程返回。線程通過執行pthread_cancel()來請求取消另一個線程,該函數在發出取消請求以後就返回了,而不需要阻塞;而實際結果由目標線程的類型和取消狀態決定(狀態可以通過函數設置的)。
 
==================================================
概要:
#include <pthread.h>
int pthread_exit(void *value_ptr );
int pthread_cancel( pthread_t thread );
int pthread_setcancelstate (int state, int *oldstate);
==================================================
 
如果線程收到cancel的請求時,處於PTHREAD_CANCEL_ENABLE,它就接受取消請求;否則如果處於PTHREAD_CANCEL_DISABLE的狀態,取消請求就會被保持在掛起狀態。默認情況下,線程處於PTHREAD_CANCEL_ENABLE狀態。
 
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章