Linux 系統下的多線程遵循POSIX線程接口,稱為pthread。編寫Linux下的多線程程序,需要使用頭文件pthread.h,連接時需要使用庫 libpthread.a。
1. 線程的創建和使用
線程的創建是用下面的幾個函數來實現的.
int
?pthread_create(pthread_t?
*
thread,pthread_attr_t?
*
attr,?
void
?
*
(
*
start_routine)(
void
?
*
),
void
?
*
arg);
void
?pthread_exit(
void
?
*
retval);
int
?pthread_join(pthread?
*
thread,
void
?
**
thread_return);
pthread_create創建一個線程,thread是用來表明創建線程的ID,attr指出線程創建時候的屬性,我們用NULL來表明使用缺省屬性.start_routine函數指針是線程創建成功后開始執行的函數,arg是這個函數的唯一一個參數.表明傳遞給start_routine 的參數.
pthread_exit函數和exit函數類似用來退出線程.這個函數結束線程,釋放函數的資源,并在最后阻塞,直到其他線程使用
pthread_join函數等待它.然后將*retval的值傳遞給**thread_return.由于這個函數釋放所以的函數資源,所以 retval不能夠指向函數的局部變量.
pthread_join和wait調用一樣用來等待指定的線程.
下面展示一個最簡單的多線程程序。
#include?
<
stdio.h
>
#include?
<
pthread.h
>
void
?thread(
void
)
{
?
int
?i;
?
for
(i
=
0
;i
<
3
;i
++
)
?printf(
"
This?is?a?pthread.\n
"
);
}
int
?main(
void
)
{
?pthread_t?id;
?
int
?i,ret;
?ret
=
pthread_create(
&
id,NULL,(
void
?
*
)?thread,NULL);
?
if
(ret
!=
0
)
?{
??printf?(
"
Create?pthread?error!\n
"
);
??exit?(
1
);
?}
?
for
(i
=
0
;i
<
3
;i
++
)
??printf(
"
This?is?the?main?process.\n
"
);
?pthread_join(id,NULL);
?
return
?(
0
);
}
2. 修改線程的屬性
上面用pthread_create函數創建了一個線程,在這個線程中,我們使用了默認參數,即將該函數的第二個參數設為NULL。屬性結構為pthread_attr_t,它同樣在頭文件/usr/include/pthread.h中定義。屬性值不能直接設置,須使用相關函數進行操作,初始化的函數為pthread_attr_init,這個函數必須在pthread_create函數之前調用。屬性對象主要包括是否綁定、是否分離、堆棧地址、堆棧大小、優先級。默認的屬性為非綁定、非分離、缺省1M的堆棧、與父進程同樣級別的優先級。
關于線程的綁定,牽涉到另外一個概念:輕進程(LWP:Light Weight Process)。輕進程可以理解為內核線程,它位于用戶層和系統層之間。系統對線程資源的分配、對線程的控制是通過輕進程來實現的,一個輕進程可以控制一個或多個線程。默認狀況下,啟動多少輕進程、哪些輕進程來控制哪些線程是由系統來控制的,這種狀況即稱為非綁定的。綁定狀況下,則顧名思義,即某個線程固定的"綁"在一個輕進程之上。被綁定的線程具有較高的響應速度,這是因為CPU時間片的調度是面向輕進程的,綁定的線程可以保證在需要的時候它總有一個輕進程可用。通過設置被綁定的輕進程的優先級和調度級可以使得綁定的線程滿足諸如實時反應之類的要求。
設置線程綁定狀態的函數為pthread_attr_setscope,它有兩個參數,第一個是指向屬性結構的指針,第二個是綁定類型,它有兩個取值:PTHREAD_SCOPE_SYSTEM(綁定的)和PTHREAD_SCOPE_PROCESS(非綁定的)。下面的代碼即創建了一個綁定的線程。
#include?
<
pthread.h
>
pthread_attr_t?attr;
pthread_t?tid;
/*
初始化屬性值,均設為默認值
*/
pthread_attr_init(
&
attr);
pthread_attr_setscope(
&
attr,?PTHREAD_SCOPE_SYSTEM);
pthread_create(
&
tid,?
&
attr,?(
void
?
*
)?my_function,?NULL);
線程的分離狀態決定一個線程以什么樣的方式來終止自己。在上面的例子中,我們采用了線程的默認屬性,即為非分離狀態,這種情況下,原有的線程等待創建的線程結束。只有當pthread_join()函數返回時,創建的線程才算終止,才能釋放自己占用的系統資源。而分離線程不是這樣子的,它沒有被其他的線程所等待,自己運行結束了,線程也就終止了,馬上釋放系統資源。程序員應該根據自己的需要,選擇適當的分離狀態。設置線程分離狀態的函數為 pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)。第二個參數可選為PTHREAD_CREATE_DETACHED(分離線程)和 PTHREAD_CREATE_JOINABLE(非分離線程)。這里要注意的一點是,如果設置一個線程為分離線程,而這個線程運行又非常快,它很可能在 pthread_create函數返回之前就終止了,它終止以后就可能將線程號和系統資源移交給其他的線程使用,這樣調用pthread_create的線程就得到了錯誤的線程號。要避免這種情況可以采取一定的同步措施,最簡單的方法之一是可以在被創建的線程里調用 pthread_cond_timewait函數,讓這個線程等待一會兒,留出足夠的時間讓函數pthread_create返回。設置一段等待時間,是在多線程編程里常用的方法。但是注意不要使用諸如wait()之類的函數,它們是使整個進程睡眠,并不能解決線程同步的問題。
另外一個可能常用的屬性是線程的優先級,它存放在結構sched_param中。用函數pthread_attr_getschedparam和函數 pthread_attr_setschedparam進行存放,一般說來,我們總是先取優先級,對取得的值修改后再存放回去。下面即是一段簡單的例子。
#include?
<
pthread.h
>
#include?
<
sched.h
>
pthread_attr_t?attr;
pthread_t?tid;
sched_param?param;
int
?newprio
=
20
;
pthread_attr_init(
&
attr);
pthread_attr_getschedparam(
&
attr,?
&
param);
param.sched_priority
=
newprio;
pthread_attr_setschedparam(
&
attr,?
&
param);
pthread_create(
&
tid,?
&
attr,?(
void
?
*
)myfunction,?myarg);
[參考]
http://fanqiang.chinaunix.net/a4/b2/20010508/113838.html
http://fanqiang.chinaunix.net/a4/b8/20010811/0905001105.html