1. 程式人生 > >Linux下的多線程

Linux下的多線程

量變 其他 thread 使用 ext bsp 傳遞 又是 常用

(1)線程的創建:pthread_create()

(2)線程返回值: 獲取方式有兩種: 1、利用線程函數直接return一個void*指針。 2、利用pthread_exit()方法,結束線程並傳遞一個void*指針返回。 二者本質是相同的,在線程中,如果使用return傳遞返回值,實際上隱式調用了pthread_exit()方法。 (3)獲取返回值: 利用pthread_join()方法,根據句柄等待相應線程執行完成,並獲取對應句柄的線程所傳遞回的返回值——一個指向某個變量的void指針。 (4)註意事項: 返回的void*型指針不可以直接指向線程內的局部變量,必須是線程外的變量值,即為全局變量或類中的相關變量。否則,當線程返回時,其內部的局部變量析構,返回的指針便指向了非法內容,會導致程序崩潰,11信號core dump。

------------------------

pthread_join聲明:

#include <pthread.h>

int pthread_join(pthread_t thread, void **value_ptr);

thread:等待退出線程的線程號。

value_ptr:退出線程的返回值。

例:

int main () { pthread_t thread1_id; pthread_t thread2_id; struct char_print_parms thread1_args; struct char_print_parms thread2_args; thread1_args.character = ’x’;
thread1_args.count = 30000; pthread_create (&thread1_id, NULL, &char_print, &thread1_args); thread2_args.character = ’o’; thread2_args.count = 20000; pthread_create (&thread2_id, NULL, &char_print, &thread2_args); pthread_join (thread1_id, NULL); pthread_join (thread2_id, NULL);
return 0; }

pthread_join的含義:使一個線程等待另一個線程結束。

pthread_join的作用:代碼中如果沒有使用pthread_join函數,主線程會很快結束導致整個進程結束,使創建的線程沒有開始執行就結束了。加入pthread_join函數後,主線程會一直等待直到pthread指定的線程結束才結束,使創建的線程有機會執行。

(所有線程都有一個線程號,也就是Thread ID。其類型為pthread_t。通過調用pthread_self()函數可以獲得自身的線程號。)

創建線程:

通過創建線程,線程將會執行一個線程函數,該線程格式必須按照下面來聲明:

void * Thread_Function(void *)

創建線程的函數如下:

int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void*), void *restrict arg);

下面說明一下各個參數的含義:

thread:所創建的線程號。

attr:所創建的線程屬性,這個將在後面詳細說明。

start_routine:即將運行的線程函數。

art:傳遞給線程函數的參數。

下面是一個簡單的創建線程例子:


linux線程編譯:

void* print_xs (void* unused) { while (1) fputc (‘x’, stderr); return NULL; } int main () { pthread_t thread_id; pthread_create (&thread_id, NULL, &print_xs, NULL); while (1) fputc (‘o’, stderr); return 0; }


在編譯的時候需要註意,由於線程創建函數在libpthread.so庫中,所以在編譯命令中需要將該庫導入。命令如下:

gcc –o createthread –lpthread createthread.c

如果想傳遞參數給線程函數,可以通過其參數arg,其類型是void *。如果你需要傳遞多個參數的話,可以考慮將這些參數組成一個結構體來傳遞。另外,由於類型是void *,所以你的參數不可以被提前釋放掉。


線程屬性:

在我們前面提到,可以通過pthread_join()函數來使主線程阻塞等待其他線程退出,這樣主線程可以清理其他線程的環境。但是還有一些線程,更喜歡自己來清理退出的狀態,他們也不願意主線程調用pthread_join來等待他們。我們將這一類線程的屬性稱為detached。如果我們在調用pthread_create()函數的時候將屬性設置為NULL,則表明我們希望所創建的線程采用默認的屬性,也就是jionable。如果需要將屬性設置為detached,則參考下面的例子:

#include ... void * start_run(void * arg) { //do some work } int main() { pthread_t thread_id; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); pthread_create(&thread_id,&attr,start_run,NULL); pthread_attr_destroy(&attr); sleep(5); exit(0); }

在線程設置為joinable後,可以調用pthread_detach()使之成為detached。但是相反的操作則不可以。還有,如果線程已經調用pthread_join()後,則再調用pthread_detach()則不會有任何效果。

結束線程:

1.return結束;2.exit結束;調用pthread_exit()結束。此外,線程甲可以被線程乙被動結束。這個通過調用pthread_cancel()來達到目的。

int pthread_cancel(pthread_t thread);

函數調用成功返回0。

當然,線程也不是被動的被別人結束。它可以通過設置自身的屬性來決定如何結束。

線程的被動結束分為兩種,一種是異步終結,另外一種是同步終結。異步終結就是當其他線程調用pthread_cancel的時候,線程就立刻被結束。而同步終結則不會立刻終結,它會繼續運行,直到到達下一個結束點(cancellation point)。當一個線程被按照默認的創建方式創建,那麽它的屬性是同步終結。

通過調用pthread_setcanceltype()來設置終結狀態。

int pthread_setcanceltype(int type, int *oldtype);

state:要設置的狀態,可以為PTHREAD_CANCEL_DEFERRED或者為PTHREAD_CANCEL_ASYNCHRONOUS。

那麽前面提到的結束點又是如何設置了?最常用的創建終結點就是調用pthread_testcancel()的地方。該函數除了檢查同步終結時的狀態,其他什麽也不做。

上面一個函數是用來設置終結狀態的。還可以通過下面的函數來設置終結類型,即該線程可不可以被終結:

int pthread_setcancelstate(int state, int *oldstate);

state:終結狀態,可以為PTHREAD_CANCEL_DISABLE或者PTHREAD_CANCEL_ENABLE。具體什麽含義大家可以通過單詞意思即可明白。

線程的本質:其實在Linux中,新建的線程並不是在原先的進程中,而是系統通過一個系統調用clone()。該系統copy了一個和原先進程完全一樣的進程,並在這個進程中執行線程函數。不過這個copy過程和fork不一樣。copy後的進程和原先的進程共享了所有的變量,運行環境。這樣,原先進程中的變量變動在copy後的進程中便能體現出來。

Linux下的多線程