1:linux thread介紹
如果需要只終止某個線程而不終止整個進程,可以有三種方法:
從線程函數return。這種方法對主線程不適用,從main函數return相當於調用exit。
一個線程可以調用pthread_cancel終止同一進程中的另一個線程。
線程可以調用pthread_exit終止自己。
#include <pthread.h>
void pthread_exit(void *value_ptr);
value_ptr是void *類型,和線程函數傳回值的用法一樣,其它線程可以調用pthread_join獲得這個指標。
需要注意,pthread_exit或者return返回的指標所指向的記憶體單元必須是全域的或者是用malloc分配的,
不能線上程函數的棧上分配,因為當其它線程得到這個返回指標時線程函數已經退出了。
#include <pthread.h>
int pthread_join(pthread_t thread, void **value_ptr);
傳回值:成功返回0,失敗返回錯誤號碼
調用該函數的線程將掛起等待,直到id為thread的線程終止。
thread線程以不同的方法終止,通過pthread_join得到的終止狀態是不同的,
總結如下:如果thread線程通過return返回,value_ptr所指向的單元裡存放的是thread線程函數的傳回值。如果thread線程被別的線程調用pthread_cancel異常終止掉,value_ptr所指向的單元裡存放的是常數PTHREAD_CANCELED。
如果thread線程是自己調用pthread_exit終止的,value_ptr所指向的單元存放的是傳給pthread_exit的參數。
下面的執行個體主要是對簡單的API進行說明:
void *thr_fn1(void *arg){printf("thread 1 returning\n");return (void *)100;}void *thr_fn2(void *arg){printf("thread 2 exiting\n");pthread_exit((void *)200);}void *thr_fn3(void *arg){while(1){printf("thread 3 writing\n");sleep(1);}}void threadexitstatus(){pthread_t tid; void *tret;pthread_create(&tid, NULL, thr_fn1, NULL);pthread_join(tid, &tret);printf("thread 1 exit code %d\n", (int)tret);pthread_create(&tid, NULL, thr_fn2, NULL);pthread_join(tid, &tret);printf("thread 2 exit code %d\n", (int)tret);pthread_create(&tid, NULL, thr_fn3, NULL);sleep(3);pthread_cancel(tid);pthread_join(tid, &tret);printf("thread 3 exit code %d\n", (int)tret);return 0;/*[root@localhost /wlan/plc/workspace/signatest/Debug]$./signatest 3thr_fn1 pid 13323 tid 3078593392 (0xb77f9b70)thread 1 returningthread 1 exit code 100thr_fn2 pid 13323 tid 3078593392 (0xb77f9b70)thread 2 exitingthread 2 exit code 200thr_fn3 pid 13323 tid 3078593392 (0xb77f9b70)thread 3 writingthread 3 writingthread 3 writingthread 3 exit code -1[root@localhost /wlan/plc/workspace/signatest/Debug]$ */}
2:linux:同步之 (Condition Variable)條件變數
線程A需要等某個條件成立才能繼續往下執行,現在這個條件不成立,線程A就阻塞等待,
而線程B在執行過程中使這個條件成立了,就喚醒線程A繼續執行。
在pthread庫中通過條件變數(Condition Variable)來阻塞等待一個條件,或者喚醒等待這個條件的線程。
Condition Variable用pthread_cond_t類型的變數表示,可以這樣初始化和銷毀:
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
傳回值:成功返回0,失敗返回錯誤號碼。和Mutex的初始化和銷毀類似,pthread_cond_init函數初始化一個Condition Variable,attr參數為NULL則表示預設屬性,pthread_cond_destroy函數銷毀一個Condition Variable。如果ConditionVariable是靜態分配的,也可以用宏定義PTHEAD_COND_INITIALIZER初始化,相當於用pthread_cond_init函數初始化並且attr參數為NULL。
#include <pthread.h>
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
傳回值:成功返回0,失敗返回錯誤號碼。
可見,一個Condition Variable總是和一個Mutex搭配使用的。pthread_cond_timedwait函數還有一個額外的參數可以設定等待逾時,如果到達了abstime所指定的時刻仍然沒有別的線程來喚醒當前線程,就返回ETIMEDOUT。
一個線程可以調用pthread_cond_signal喚醒在某個Condition Variable上等待的另一個線程,也可以調用pthread_cond_broadcast喚醒在這個Condition Variable上等待的所有線程。
//分別對條件變數和互斥量進行初始化。
static pthread_mutex_t pthreadmtx = PTHREAD_MUTEX_INITIALIZER;static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;static int avail = 0;static int productNum = 0;static void * threadFunc(void *arg){ int cnt = atoi((char *) arg); int s, j; printf("need Num:%d \n",cnt); while(1) { usleep(2);// sleep(2); // sleep(1); /* Code to produce a unit omitted */ s = pthread_mutex_lock(&pthreadmtx); if (s != 0) errExitEN(s, "pthread_mutex_lock"); avail++; /* Let consumer know another unit is available */ productNum++; printf("Num Product:%d\n",productNum); s = pthread_mutex_unlock(&pthreadmtx); if (s != 0) errExitEN(s, "pthread_mutex_unlock"); s = pthread_cond_signal(&cond); /* Wake sleeping consumer */ if (s != 0) errExitEN(s, "pthread_cond_signal"); } return NULL;}void threadConditionMutex(int argc, char *argv[]){ pthread_t tid; int s, j; int totRequired; /* Total number of units that all threadswill produce */ int numConsumed; /* Total units so far consumed */ Boolean done; time_t t; struct timespec request; struct timeval start; t = time(NULL); /* Create all threads */ totRequired = 0; { totRequired += atoi(argv[1]); s = pthread_create(&tid, NULL, threadFunc, argv[1]); if (s != 0) errExitEN(s, "pthread_create"); } /* Use a polling loop to check for available units */ numConsumed = 0; done = FALSE; for (;;) { s = pthread_mutex_lock(&pthreadmtx); if (s != 0) errExitEN(s, "pthread_mutex_lock"); if (gettimeofday(&start, NULL) == -1) errExit("gettimeofday"); request.tv_sec = start.tv_sec+1; request.tv_nsec = start.tv_usec*1000; // s = pthread_cond_wait(&cond, &pthreadmtx); s = pthread_cond_timedwait(&cond, &pthreadmtx,&request); if (s == 0) { /* Consume all ava *ilable units*/ numConsumed ++; avail--; printf("T=%ld: numConsumed=%d avail:%d\n", (long) (time(NULL) - t),numConsumed,avail); done = numConsumed >= totRequired; } else { printf("pthread_cond_timedwait timeout...............\n"); } s = pthread_mutex_unlock(&pthreadmtx); if (s != 0) errExitEN(s, "pthread_mutex_unlock"); if (done) break; usleep(200); } exit(EXIT_SUCCESS);}
3:linux Semaphore 訊號量
訊號量(Semaphore)和Mutex類似,表示可用資源的數量,和Mutex不同的是這個數量可以大於1。
POSIX semaphore訊號量不僅可用於同一進程的線程間同步,也可用於不同進程間的同步。
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_post(sem_t * sem);
int sem_destroy(sem_t * sem);
semaphore變數的類型為sem_t,sem_init()初始化一個semaphore變數,value參數表示可用資源的數量,
pshared參數為0表示訊號量用於同一進程的線程間同步,
在用完semaphore變數之後應該調用sem_destroy()釋放與semaphore相關的資源。
調用sem_wait()可以獲得資源,使semaphore的值減1,如果調用sem_wait()時semaphore的值已經是0,
則掛起等待。如果不希望掛起等待,可以調用sem_trywait()。
調用sem_post()可以釋放資源,使semaphore的值加1,同時喚醒掛起等待的線程。
範例程式碼如下:
#include <semaphore.h>#define NUM 5int queue[NUM];sem_t blank_number, product_number;int product_num =0;int consum_num =0;void *producer(void *arg){ int p = 0;while (1){sem_wait(&blank_number);queue[p] = p;printf("Produce %d\n", queue[p]);product_num++;sem_post(&product_number);p = (p+1)%NUM;sleep(1);}}void *consumer(void *arg){int c = 0;while (1){sem_wait(&product_number);printf("Consume %d\n", queue[c]);queue[c] = 0;consum_num++;sem_post(&blank_number);c = (c+1)%NUM;sleep(1);}}void semtest(){pthread_t pid, cid;sem_init(&blank_number, 0, NUM);sem_init(&product_number, 0, 2);pthread_create(&pid, NULL, producer, NULL);sleep(4);pthread_create(&cid, NULL, consumer, NULL);while(1){printf("product_num:%d \t consum_num:%d avail:%d\n",product_num,consum_num,(product_num-consum_num));sleep(1);}pthread_join(pid, NULL);pthread_join(cid, NULL);sem_destroy(&blank_number);sem_destroy(&product_number);return 0;}