線程建立函數:
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine)(void*), void *arg);
參數
thread:傳回線程ID。
attr:設定線程的屬性,attr為NULL表⽰示使⽤用預設屬性。
start_routine:是個函數位址,線程啟動後要執⾏行的函數。
arg:傳給線程啟動函數的參數。
傳回值:成功傳回;失敗傳回錯誤碼。
一般用pthread_create函數建立新線程。下面是利用pthread_create函數建立新線程的代碼:
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
void *thread_run(void *arg)
{
while()
{
printf("I am a thread!\n");
sleep();
}
}
int main(void)
{
pthread_t tid;
pthread_create(&tid, NULL, thread_run, NULL);
while()
{
printf("I am thread group!\n");
sleep();
}
return ;
}
代碼中兩個線程都每隔一秒向螢幕列印字元串,來看看執行效果:
也可以取得線程的線程ID:
#include <pthread.h>
pthread_t pthread_self(void);
傳回值:調用線程的ID。
這裡取得線程庫pthread範圍的線程ID,傳回值為pthread_t類型資料, pthread_t 的具體類型取決于實作,Linux的NPTL實作中,pthread_t類型的線程ID,本質上是一個程序位址空間的位址。
也可以用:
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
pid_t tid;
tid = syscall(SYS_gettid);
這裡取得核心級線程的線程ID,即pid。
可以将上面的代碼稍微改一下:
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#define _GNU_SOURCE
void *thread_run(void *arg)
{
pthread_t tid = pthread_self();
pid_t pid = syscall(SYS_gettid);
while()
{
printf("I am a thread! user: %p, kernel: %d\n", tid, pid);
sleep();
}
}
int main(void)
{
pthread_t tid;
pthread_create(&tid, NULL, thread_run, NULL);
pthread_t ptid = pthread_self();
pid_t pid = syscall(SYS_gettid);
while()
{
printf("I am thread group! user: %p, kernel: %d\n", ptid, pid);
sleep();
}
return ;
}
運作代碼可以得到這樣的輸出:
在多線程程序中,任何一個線程的異常終止都會導緻整個程序的退出,如果僅要求線程退出而不終止整個程序可用下面三種方法:
1. 從線程函數return。這種⽅方法對主線程不适⽤用,從main函數return相當于調⽤用exit。
2. 線程可以調⽤用pthread_ exit終⽌止⾃自⼰己。
3. ⼀一個線程可以調⽤用pthread_ cancel終⽌止同⼀一程序中的另⼀一個線程。
pthread_exit函數:
void pthread_exit(void *value_ptr);
功能:程序終止。
參數
value_ptr:value_ptr不要指向⼀個局部變量。
傳回值:⽆傳回值,跟程序一樣,線程結束的時候⽆無法傳回到它的調用者(自身)。
注意,這裡的傳回值必須是全局的或用malloc配置設定的,不能是函數棧上的指針,因為當其他線程得到這個傳回值時線程函數已經退出了。
pthread_cancel函數:
int pthread_cancel(pthread_t thread);
功能:取消一個執行中的線程。
參數
thread:線程ID。
傳回值:成功傳回;失敗傳回錯誤碼
要取得線程的傳回值,就要用到程序等待函數pthread_join:
int pthread_join(pthread_t thread, void **value_ptr);
功能:等待線程結束,調用該函數的線程将挂起等待,直到id為thread的線程終⽌。
參數
thread:線程ID
value_ptr:它指向⼀個指針,後者指向線程的傳回值
傳回值:成功傳回;失敗傳回錯誤碼
新建立的線程預設為是joinable的,即可結合的,當線程退出後必須程序pthread_join操作。因為線程退出後其空間不能自動釋放,必須顯式回收,如果不進行釋放的話新建立的線程不會複用剛剛的位址空間,這樣就造成了記憶體洩漏。
線程以不同的方法終止,通過pthread_join得到的終止狀态是不同的,總結如下:
1. 如果thread線程通過return傳回,value_ ptr所指向的單元⾥裡存放的是thread線程函數的傳回值。
2. 如果thread線程被别的線程調用pthread_ cancel異常終掉,value_ ptr所指向的單元裡存放的是常數PTHREAD_ CANCELED。
3. 如果thread線程是自己調用pthreadexit 終止的 ,valueptr所指向的單元存放的是傳給pthread_exit的參數。
4. 如果對thread線程的終止狀态不感興趣,可以傳NULL給value_ ptr參數。
代碼:
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#define _GNU_SOURCE
void *thread_run1(void *arg)
{
printf("%s\n", (char*)arg);
int *p = (int*)malloc(sizeof(int));
*p = ;
sleep();
return (void*)p;
}
void *thread_run2(void *arg)
{
printf("%s\n", (char*)arg);
int *p = (int*)malloc(sizeof(int));
*p = ;
sleep();
pthread_exit((void*)p);
}
void *thread_run3(void *arg)
{
printf("%s\n", (char*)arg);
while();
}
int main(void)
{
pthread_t tid1, tid2, tid3;
void *ret1, *ret2, *ret3;
pthread_create(&tid1, NULL, thread_run1, "thread No1");
pthread_create(&tid2, NULL, thread_run2, "thread No2");
pthread_create(&tid3, NULL, thread_run3, "thread No3");
//sleep(1);
pthread_cancel(tid3);
pthread_join(tid1, &ret1);
printf("thread quit! thread id : %X, return code : %d\n", tid1, *(int*)ret1);
free(ret1);
pthread_join(tid2, &ret2);
printf("thread quit! thread id : %X, return code : %d\n", tid2, *(int*)ret2);
free(ret2);
pthread_join(tid3, &ret3);
if(ret3 == PTHREAD_CANCELED)
printf("thread quit! thread id : %X, return code : PTHREAD_CANCELED\n", tid3);
else
printf("thread quit! thread id : %X, return code : NULL\n", tid3);
return ;
}
運作結果:
新建立的線程是可結合的,即需要調用pthread_join進行回收,而如果不需要線程函數的傳回值,那麼join就是一種負擔,此時我們可以将線程聲明為“分離”的,即當線程結束後系統自動釋放線程資源。
#include <pthread.h>
int pthread_detach(pthread_t thread);
功能:對線程thread進行分離。
傳回值:成功傳回;錯誤傳回錯誤編号。
線程也可以自己分離:
pthread_detach(pthread_self());
joinable與分離是沖突的,是以一個線程不能同時是joinable和分離的。
代碼:
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#define _GNU_SOURCE
void *thread_run(void *arg)
{
pthread_detach(pthread_self());
printf("%s\n", (char*)arg);
return NULL;
}
int main(void)
{
pthread_t tid;
if(pthread_create(&tid, NULL, thread_run, "thread run") != )
{
printf("create thread errno\n");
return ;
}
printf("I am thread group!\n");
sleep();
if(pthread_join(tid, NULL) == )
printf("thread wait success\n");
else
printf("thread wait failed\n");
return ;
}
先派生出一個線程,這個線程自己分離後執行後續操作,主線程調用pthread_join,如果等待成功則輸出“thread wait success”,失敗則輸出“thread wait failed”,來看運作結果:
顯然派生出的線程自動進行線程分離,主線程等待失敗。