這篇文章先講一些線程辨別和建立,會在下一篇文章中介紹線程同步。
本章介紹線程篇,第一篇先着重講線程辨別,建立,終止以及一些需要注意的東西,後續繼續更新線程同步。
一、線程辨別
就像每個程序擁有一個自己的程序ID一樣,每個線程也擁有自己的一個線程ID。程序ID在整個系統中是唯一的,但是線程ID不同,它隻在它所屬的程序環境中有效。程序id有個資料類型pid_t來表示,他是個非負整數。線程id則用pthread_t資料類型來表示,但是這個資料類型在移植的時候不能
簡單的當成整數來處理,是以需要使用函數來判定兩個線程id是否相等;
#include <pthread.h>
int pthread_equal(pthread_t tid1,pthread_t tid2);//若相等則傳回非0值,否則傳回0
線程需要擷取自己的id可使用pthread_self()函數擷取
#include <pthread.h>
pthread_t pthread_self(void);
二、線程建立
新增線程的建立可以調用pthread_create函數建立;
#include <pthread.h>
int pthread_create(pthread_t *tid,const pthread_attr_t *attr,void *(*start)(void),void *arg);//成功傳回0,失敗傳回錯誤編号
當pthread_create成功傳回時,tid指向的記憶體單元被設定為新建立線程的線程id。
attr參數用于定制各種不同的線程屬性,可設定為NULL,建立線程時會使用預設的屬性。
新建立的線程從start函數的位址開始運作,該函數隻有一個無類型的指針參數arg,如果需要向start函數傳遞多個參數,需要把這些參數放到一個結構中,然後把這個結構的位址作為arg參數傳入。
線程建立後并不能保證哪個線程先運作,可能是新建立的線程,也可能是調用線程。新建立的線程可以通路程序的位址空間,并且繼承調用線程
的浮點環境和信号屏蔽字,但是該線程的未決信号集被清除。
例子:
#include <pthread.h>
#include <stdio.h>
pthread_t ntid;
void printids(const char* src)
{
pid_t pid;
pthread_t tid;
pid = getpid();
tid = pthread_self();
pthread("%s pid:%u, tid:%u (0x%x)\n",src,(unsigned int pid),(unsigned int)tid,(unsigned int)tid);
}
void *thr_fn(*arg)
{
printids("new thread:");
return (void*)0;
}
int main()
{
int err;
err = pthread_create(&ntid,NULL,thr_fn,NULL);
if(0 != err)
printf("create pthread err:%s\n",strerror(err));
printids("main thread:");
sleep(1);
exit(0);
}
這個例子要說明兩個問題:
1、要處理主線程和新線程之間的競争,是以主線程要用sleep,否則,因主線程和新線程誰先運作的不确定性,新線程可能在運作之前
主線程已經退出了。導緻新線程無法運作。
2、新線程擷取自己的id要使用pthread_self()函數擷取,不能從全局變量ntid得到,因為新線程可能在主線程之前運作,這樣直接
擷取的ntid是不正确的。
linux下線程id比較合理,但是程序id的擷取卻并不比對,這和linux線程的實作有關,linux使用clone系統調用來實作pthread_create,
clone系統調用建立子程序,這個子程序可以共享父程序一定數量的執行環境,而且這個數量可配。
三、線程終止
程序的任意線程調用了exit,_Exit,_exit,那麼整個程序就會終止。以此類似,如果信号的預設動作是終止程序,那麼将該信号發
送到線程也會終止整個程序。
單個線程有三種方式退出,在不終止整個程序的情況下停止它的控制流
1、線程訓示從啟動曆程中傳回,傳回值是線程的終止碼
2、線程可以被統一程序中的其他線程終止取消
3、線程調用pthread_exit。
#include <pthread>
void pthread_exit(void *rval_ptr);
rval_ptr是無類型的,程序中的其他線程可以調用pthread_join函數通路擷取到這個值
int pthread_join(pthread_t thread,void *rval_ptr);//成功傳回0,出錯傳回錯誤編号
調用者将一直阻塞,直到指定線程調用pthread_exit,或傳回,或被取消。如果線程被取消,rval_ptr值為PTHREAD_CANCELED,線程可以設定為分離狀态,如果線程已經設定為分離狀态,那麼調用pthread_join就會失敗,傳回EINVAL.
注意pthread_exit調用的傳回值所指向的記憶體線上程終止後要合法的,否則主線程去通路這個指針指向記憶體會出現非法通路的問題。
例子比較少,會在後續持續更新,希望繼續關注!