====本文系本站原創,歡迎轉載! 轉載請註明出處:http://blog.csdn.net/yyplc====
用Posix thread進行多線程設計,就不怕跨平台了,因為很多OS都相容Posix thread,如Linux/Windows等,甚至嵌入式系統上(如rt-thread)都支援posix thread API。線程有比進程體積小,速率高,速度快等優勢。所以編程時,如果涉及到效率和速度時,採用pthread_create()一個線程總比fork()一個進程好些。
Posxi thread 線程操作主要有建立(creation),終止(termination),同步(joins,blocking),調度(scheduling),資料管理(datamanagement)和互動(interaction).
可以從以下線程框圖瞭解線程的構架:
多線程間關係:
多線程間共用記憶體模型:
與普通的fork()進程不一樣,線程很簡單,線程並不需要維護線程列表,也不需要知道誰建立了它。以下是pthread_create()與fork()在各種平台上,效能的比較:
- The primary motivation for using Pthreads is to realize potential program performance gains.
- When compared to the cost of creating and managing a process, a thread can be created with much less operating system overhead. Managing threads requires fewer system resources than managing processes.
For example, the following table compares timingresults for the fork() subroutineand the pthread_create() subroutine.Timings reflect 50,000 process/thread creations, were performed with the time utility, and units are in
seconds, nooptimization flags.
Note: don't expect the sytem and user times toadd up to real time, because these are SMP systems with multiple CPUs workingon the problem at the same time. At best, these are approximations run on localmachines, past and present.
Platform |
fork() |
pthread_create() |
real |
user |
sys |
real |
user |
sys |
Intel 2.8 GHz Xeon 5660 (12cpus/node) |
4.4 |
0.4 |
4.3 |
0.7 |
0.2 |
0.5 |
AMD 2.3 GHz Opteron (16cpus/node) |
12.5 |
1.0 |
12.5 |
1.2 |
0.2 |
1.3 |
AMD 2.4 GHz Opteron (8cpus/node) |
17.6 |
2.2 |
15.7 |
1.4 |
0.3 |
1.3 |
IBM 4.0 GHz POWER6 (8cpus/node) |
9.5 |
0.6 |
8.8 |
1.6 |
0.1 |
0.4 |
IBM 1.9 GHz POWER5 p5-575 (8cpus/node) |
64.2 |
30.7 |
27.6 |
1.7 |
0.6 |
1.1 |
IBM 1.5 GHz POWER4 (8cpus/node) |
104.5 |
48.6 |
47.2 |
2.1 |
1.0 |
1.5 |
INTEL 2.4 GHz Xeon (2 cpus/node) |
54.9 |
1.5 |
20.8 |
1.6 |
0.7 |
0.9 |
INTEL 1.4 GHz Itanium2 (4 cpus/node) |
54.5 |
1.1 |
22.2 |
2.0 |
1.2 |
0.6 |
在同一個線程或進程中所建立的線程共同享有一樣的地址空間。
線程間共用:
.進程指令(process instructions)
.大部分資料(most data)
.檔案(descriptors)
.訊號和訊號控制代碼(signals and signal handlers)
.當前工作目錄(current working directory)
.使用者和組id(user and group id)
線程獨自屬性:
.線程id(thread id)
.寄存器(內容)和棧不同(set of registers,stack pointer)
.局部變數,返回地址(stack for local variables,return addresses)
.訊號mask(signal mask)
.優先順序(priority)
.傳回值(return value errno)
主要的操作函數:
/*建立一個線程,成功返回0,失敗返回error錯誤標誌*/
int pthread_create(pthread_t * thread, //thread :線程id, unsigned long intxi型 const pthread_attr_t *attr, //attr: 線程屬性參數,建立時將根據這個參數進行線程初始化 void *(*start_routine)(void *), //start_routine:指向線程所調用的函數 void *arg); //arg :線程傳遞參數
/* 終止線程,成功返回0,失敗返回error錯誤 標誌*/
void pthread_exit(void *retval); //retval:傳回值指標
/*等待直到id為th線程運行結束(合并一個線程的意思)*/
int pthread_join(pthread_t th, void**thread_return); // th:線程id // thread_return :線程終止或取消時的傳回值指標
/*擷取當前線程id*/
pthread_t pthread_self(void);
線程的同步機制:
.互斥量(mutexes)
.串連/合并(joins)
.條件變數(condition variables)
/*線程間互斥量操作函數,顧名思義*/
int pthread_mutex_lock(pthread_mutex_t*mutex);//擷取mutex,成功返0,失敗返回錯誤標誌,並阻塞當前線程 intpthread_mutex_trylock(pthread_mutex_t *mutex); //同上,不同的是多了個try(也就是說先try一下) //如果在當前線程中,如果同一個互斥量已經被當前線程鎖住,pthread_mutex_tyrlock將立即返回(成功).如果互斥量類型為:PTHREAD_MUTEX_RECURSIVE那麼mutexlock count將自加一,然後立即返回(成功) int pthread_mutex_unlock(pthread_mutex_t*mutex); //釋放一個mutex
實現原理:互斥量用於多線程對臨界資源的訪問,通過mutex lock count來判定是否鎖住,初始值為0,當pthread_mutex_lock時mutex lock_count 自加,pthread_mutex_unlock時將mutex_lock_count自減。所以互斥量可用時mutex_lock_count = 0,對於一個臨界資源,使用前應先lock,使用完後再unlock,如果使用不當,會有意外發生,但如果先unlock那麼mutex_lock_count 自減1,說明改互斥量將可以同時使用2次了。
條件變數操作函數:
/*初始化一個條件變數cond(布爾型),成功返回0,失敗返回error錯誤標誌*/
int pthread_cond_init(pthread_cond_t *restrictcond, const pthread_condattr_t*restrict attr);
/*銷毀一個條件變數cond,成功返回0,失敗返回error錯誤標誌*/
int pthread_cond_destroy(pthread_cond_t*cond);
/*釋放一個互斥量且等待(即阻塞當前線程)一個條件變數cond為真,後再lock*/
int pthread_cond_timedwait(pthread_cond_t*restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrictabstime);//等待條件變數cond是否為真,時限為abstime int pthread_cond_wait(pthread_cond_t*restrict cond, pthread_mutex_t *restrict mutex); //等待條件cond是否為真,時限為cond真為止
/*釋放條件變數cond,喚醒先前已被阻塞的線程*/
intpthread_cond_broadcast(pthread_cond_t *cond);//喚醒所有因條件變數cond而阻塞的線程 intpthread_cond_signal(pthread_cond_t *cond);//喚醒一個因條件變數cond而阻塞的線程
編程執行個體:
完成一個有趣的遊戲(類似搶板凳):主線程中建立線程1,然後線程1再建立2個線程2,3,線程2,3分別對一個計數器操作counter(初值為0),線程1每使用一次加3,線程2每使用一次加5,如果加到被15整除,那麼counter加8,看哪個線程先加到9999,並計算自己使用了多少次計算機。先到者勝利,並列印出相應資訊。
實現代碼:
#include<pthread.h>#include<stdlib.h>#include<unistd.h>#include<stdio.h> #defineCOUNTER_MAX 9999static intCOUNTER;struct RESULT { pthread_t tid; int cnt1; int cnt2;};static structRESULT res;staticpthread_mutex_t mux = PTHREAD_MUTEX_INITIALIZER;staticpthread_cond_t cond =PTHREAD_COND_INITIALIZER; static void *thread2(void *arg){ int ret; printf("enter thread2, tid =%lu\n",pthread_self()); sleep(1); for (;;) { pthread_mutex_lock(&mux); if(COUNTER >= COUNTER_MAX) { ret = pthread_cond_signal(&cond); //喚醒一個因條件變數cond而阻塞的線程 if (ret) printf("error in thread2\n"); res.tid = pthread_self(); pthread_mutex_unlock(&mux); //釋放mux pthread_exit(0); } printf("."); fflush(stdout); COUNTER += 3; if(COUNTER%15 == 0 && COUNTER) { COUNTER += 8; usleep(50*res.cnt1); } res.cnt1++; pthread_mutex_unlock(&mux); usleep(COUNTER); }} static void *thread3(void *arg){ int ret; printf("enter thread3, tid =%lu\n",pthread_self()); sleep(1); for (;;) { pthread_mutex_lock(&mux); if(COUNTER >= COUNTER_MAX) { ret = pthread_cond_signal(&cond); //喚醒一個因條件變數cond而阻塞的線程 if (ret) printf("error in thread3\n"); res.tid = pthread_self(); pthread_mutex_unlock(&mux); //釋放mux pthread_exit(0); } printf("o"); fflush(stdout); COUNTER += 5; if(COUNTER%15 == 0 && COUNTER) { COUNTER += 8; usleep(50*res.cnt2); } res.cnt2++; pthread_mutex_unlock(&mux); usleep(COUNTER); }} static void *thread1(void *arg){ int ret; pthread_t tid2,tid3; printf("starting...\n"); pthread_mutex_lock(&mux); ret =pthread_create(&tid2,NULL,thread2,NULL); if (ret) { printf("create thread1 error\n"); } ret =pthread_create(&tid3,NULL,thread3,NULL); if (ret) { printf("create thread2 error\n"); } pthread_cond_wait(&cond,&mux); //釋放mux,等待cond為真 if (res.tid == tid2) { pthread_cancel(tid2); } else { pthread_cancel(tid3); } printf("\nget the winner:\n%s, tid= %lu,",(res.tid==tid2?"thread2":"thread3"),res.tid); printf("cnt1 = %d,cnt2 =%d\n",res.cnt1,res.cnt2); pthread_mutex_unlock(&mux); pthread_exit(0);} int main(void){ int ret; pthread_t tid1; ret =pthread_create(&tid1,NULL,thread1,NULL); if (ret) { printf("create thread1 error\n"); } if (pthread_join(tid1,NULL)) { //等待thread1結束 printf("error in thread1\n"); } exit(0);}測試結果:
starting...enter thread3, tid= 3062217584enter thread2, tid= 3070610288o..o.o.o.o.o.o.o.o.oo..oo..o.o.o..oo..oo..o.o.o..oo..oo.o.o.o.o.o.o.o.o.o..oo..oo.o.o.o.o.o.o.o..oo.o..oo..o.o.o.o.o.o.o..o.oo.o.oo..oo.o.o.o.oo.o.o.o.o.o.o.o.o.o.o..o.oo.o.o.oo.o.o.o.o.o.o.o.o.o.o.o..oo..o.o..oo.o.o.o..o.o.o..o.o.o.o.oo.o.o.oo.o.o.o.o.o.o.o.o.o..o.oo..oo.o.oo.o..o.o.o.o..o.oo.o..o.o.o.o.o..o.oo.o.o.o.o.oo.o.o.oo.o.o.oo..oo.o.oo.o..o.o.o.o..o.oo..o.o.o.o..o.o.o.oo.o.oo.o.o.o.oo..oo.o.o.oo.o.o.oo..o.o.o.o..o.o.oo.o.o.o.oo..o.o..o.o.o.oo.o.o.oo.o..o.o..o.o.oo.o.o.o.oo.o..o.o.o..o.oo..o.o.o..o.o.o.o.oo.o.o.oo.o.o.o.o.oo.o.oo.o.o.o.oo.o.o.o.o.oo.o.o.oo.o..o.o..o.o.o.o.oo.o.o.oo.o.o.o.oo..o.o.o..o.oo.o.o.o.oo.o.o.o.oo.o.o.o.o.o.oo.o.o.oo.o.o.o.oo.o.o.o.oo.o.o.oo.o.o.o.oo.o.o.o.o.o.o.o.o.o..o.o.o.o.o.o..o.o.o.oo.o.o.oo.o.o.o.o.o.oo.o.o.oo.o.o.o.oo.o.o.o.oo.o.o.oo.o.o.o.o.o.o.o.o.o.o..o.oo.o..o.o.o.o.o..o.oo.o.o.o.oo.o.o.o.oo.o.o.o.o.oo.o.o.o.o.o.o.o.o.o..o.o.oo.o.o.oo.o.o.o.oo.o.o.o.oo.o.o.o.oo.o.o.o.oo.o.o.o.oo.o.o.oo.o..o.o.o..o.o.oo.o.o.o.o.oo.o.o.o.o.o.o.o.o..o.o.o.o.o.o.o..o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.oo.o.o.o.o.o.o.o.o.o.o.o.o..o.o.o.o.o..o.o.o.o.o.o.o.o.o.o.o.o.o.oo.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o..o.o.o.o.o.o.o..o.o..o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o..o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.oo.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.oget the winner:thread2, tid =3070610288,cnt1 = 1046,cnt2 = 1072