pthread-win32 semaphore信号量总结
最近的多線程 想實現(xiàn)這樣的功能: 多線程Socket獲得的數(shù)據(jù) 對其進行某種處理FuncA,但是FuncA比較耗時,希望能夠單獨獨立出來,這樣 接受和處理數(shù)據(jù)分開,但是FuncA處理數(shù)據(jù)不能放入一個線程,否則很慢,要多線程處理,這個時候 就要使用 多線程 信號量 semaphore了?!疚沂窃趙indows下 使用pthread win32 的】
在pthread win32源碼中,semaphore.h是這樣定義的:
typedef struct sem_t_ * sem_t;
下面是這個結(jié)構(gòu)的定義
/** ====================* ====================* Semaphores, Mutexes and Condition Variables* ====================* ====================*/struct sem_t_ {int value;pthread_mutex_t lock;HANDLE sem; #if defined(NEED_SEM)int leftToUnblock; #endif };其方法有:
int sem_init (sem_t * sem,int pshared,unsigned int value);int sem_destroy (sem_t * sem);int sem_trywait (sem_t * sem);int sem_wait (sem_t * sem);int sem_timedwait (sem_t * sem,const struct timespec * abstime);int sem_post (sem_t * sem);int sem_post_multiple (sem_t * sem,int count);int sem_getvalue (sem_t * sem,int * sval); //沒有實現(xiàn)的有int sem_open (const char * name,int oflag,mode_t mode,unsigned int value);int sem_close (sem_t * sem);int sem_unlink (const char * name);沒有實現(xiàn)的 函數(shù)代碼都是類似下面這樣的,直接是返回錯誤:
int sem_open (const char *name, int oflag, mode_t mode, unsigned int value) { printf("本函數(shù)沒有實現(xiàn)\n");//本人添加的 以免誤用errno = ENOSYS;return -1; } /* sem_open */好,下面說重點了,sem_t 就是 semaphore信號量 怎么用。
1、定義sem_t結(jié)構(gòu)體
sem_t 就是一個結(jié)構(gòu)體指針,定義了,是沒有值的。比如
sem_t sem=NULL;2、初始化sem_t變量
sem_init(&sem,0,0);顯然內(nèi)部會分配內(nèi)存,返回值為0,如果失敗為非0【其實是-1,只有兩種返回值,納悶為什么不用boolean】,錯誤存儲在errno中。
第二個參數(shù) 為0,為1 是可以在多進程中使用,但是pthread win32沒有實現(xiàn),所以保證永遠為0;
第三個參數(shù)是初始值,如果大于0,則會發(fā)送多少個sem_post操作的。一般設置0 即可。
3、在多線程中 等待
sem_wait(&sem);sem_timedwait(&sem,?const struct timespec *abstime));sem_trywait(&sem);?sem_wait是阻塞的,sem_timewait是阻塞一定時間后繼續(xù),sem_trywait是非阻塞的,非阻塞怎么用,我暫時沒研究。
總之呢,wait之后,內(nèi)部value就會-1;所以如果vaue小于0,那么就有線程正在等待,否則就不等待直接進行下面的工作了。
4、【重點】在主線程或其他地方 發(fā)送post,讓那些工作線程逐個開始工作起來
sem_post(&sem);//讓value+1
sem_post_multi(&sem,5);?//讓vaue+5
5、當然就是結(jié)束了,當且僅當 sem有效 且 內(nèi)部value>=0的時候,也就是沒有sem_wait的時候可以銷毀。
sem_destroy(&sem);
此時 sem_wait 就會失敗了。所以destroy前 先 sem_post? value的絕對值 個信號 就可以了。
6、【補充】獲得sem內(nèi)部的value值,當且僅當==0的時候,才可以destroy,小于0 隊列個數(shù),大于0 排隊數(shù)量。
sem_getvalue(&sem,&theOutValue);
?
以上返回值為0 正常,否則不正常。
使用這個semaphore有一個好處,比如,只有2個線程,你一下子sem_post 20次,沒關系,sem_wait會執(zhí)行20次的,而且是2個線程輪流。其及時對WINAPI semaphore的一個封裝。
?
?semaphore如果在一個線程中使用,一般叫做 binary semaphore,單值。
?ps:signal.h 頭文件 叫做信號 ,與這個semaphore信號量 不太一樣的。
附上 臨界區(qū),互斥量,信號量,事件的區(qū)別 ,這些都屬于? 線程安全的范疇,不知道還有別的沒有了。
View Code 臨界區(qū),互斥量,信號量,事件的區(qū)別 =================================== 四種進程或線程同步互斥的控制方法 1、臨界區(qū):通過對多線程的串行化來訪問公共資源或一段代碼,速度快,適合控制數(shù)據(jù)訪問。 2、互斥量:為協(xié)調(diào)共同對一個共享資源的單獨訪問而設計的。 3、信號量:為控制一個具有有限數(shù)量用戶資源而設計。 4、事 件:用來通知線程有一些事件已發(fā)生,從而啟動后繼任務的開始。臨界區(qū)(Critical Section)(同一個進程內(nèi),實現(xiàn)互斥) =================================== 保證在某一時刻只有一個線程能訪問數(shù)據(jù)的簡便辦法。在任意時刻只允許一個線程對共享資源進行訪問。如果有多個線程試圖同時訪問臨界區(qū),那么在有一個線程進入后其他所有試圖訪問此臨界區(qū)的線程將被掛起,并一直持續(xù)到進入臨界區(qū)的線程離開。臨界區(qū)在被釋放后,其他線程可以繼續(xù)搶占,并以此達到用原子方式操作共享資源的目的。互斥量(Mutex)(可以跨進程,實現(xiàn)互斥) =================================== 互斥量跟臨界區(qū)很相似,只有擁有互斥對象的線程才具有訪問資源的權(quán)限,由于互斥對象只有一個,因此就決定了任何情況下此共享資源都不會同時被多個線程所訪問。當前占據(jù)資源的線程在任務處理完后應將擁有的互斥對象交出,以便其他線程在獲得后得以訪問資源?;コ饬勘扰R界區(qū)復雜。因為使用互斥不僅僅能夠在同一應用程序不同線程中實現(xiàn)資源的安全共享,而且可以在不同應用程序的線程之間實現(xiàn)對資源的安全共享。 互斥量與臨界區(qū)的作用非常相似,但互斥量是可以命名的,也就是說它可以跨越進程使用。所以創(chuàng)建互斥量需要的資源更多,所以如果只為了在進程內(nèi)部是用的話使用臨界區(qū)會帶來速度上的優(yōu)勢并能夠減少資源占用量。信號量(Semaphores)(主要是實現(xiàn)同步,可以跨進程) =================================== 信號量對象對線程的同步方式與前面幾種方法不同,信號允許多個線程同時使用共享資源,這與操作系統(tǒng)中的PV操作相同。它指出了同時訪問共享資源的線程最大數(shù)目。它允許多個線程在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大線程數(shù)目。一般是將當前可用資源計數(shù)設置為最大資源計數(shù),每增加一個線程對共享資源的訪問,當前可用資源計數(shù)就會減1,只要當前可用資源計數(shù)是大于0的,就可以發(fā)出信號量信號。但是當前可用計數(shù)減小到0時則說明當前占用資源的線程數(shù)已經(jīng)達到了所允許的最大數(shù)目,不能在允許其他線程的進入,此時的信號量信號將無法發(fā)出事件(Event)(實現(xiàn)同步,可以跨進程) =================================== 事件對象也可以通過通知操作的方式來保持線程的同步。并且可以實現(xiàn)不同進程中的線程同步操作。?參考:
http://baike.baidu.com/view/1499210.htm
http://networking.ctocio.com.cn/tips/180/9333180.shtml
?
最后附上我自己的測試源代碼:
View Code #include <stdio.h> #include <pthread.h> #include <sched.h> #include <semaphore.h> #include <conio.h>//for getch() #include <ctype.h>#include<Windows.h> #pragma comment(lib, "pthreadVC2.lib") //必須加上這句sem_t sem; void*SemThreadWorker(void* Param) {printf("#1 [child %s]I am Waiting\n",Param); //sem_wait(&sem); //sem_timedwait(&sem,60); //sem_trywait(&sem);while(0==sem_wait(&sem)) {// Wait semaphoreprintf(" [child %s]I am Working in 1 second!!\n",Param);Sleep(1000);}printf("#2 [child %s]I am Exit\n",Param);return (void *)10; }int main() {int ret=0;ret=sem_init(&sem,0/*int pshared process_shared*/,0/*uint init_value*/);/*SEM_VALUE_MAX == int_max*/if(ret!=0){printf("Semaphore initialize failed");exit(EXIT_FAILURE);}if(0==sem_getvalue(&sem,&ret)){printf("\n sem_getvalue value=%d \n",ret);}else{perror("@Error sem_getValue");}//CreateThreadspthread_t tids[5];ret = pthread_create(&tids[0], NULL, SemThreadWorker, "1"); if (ret) {printf("Thread creation failed!!\n");exit(EXIT_FAILURE);}ret = pthread_create(&tids[1], NULL, SemThreadWorker, "2"); if (ret) {printf("Thread creation failed!!\n");exit(EXIT_FAILURE);}ret = pthread_create(&tids[2], NULL, SemThreadWorker, "3"); if (ret) {printf("Thread creation failed!!\n");exit(EXIT_FAILURE);}ret = pthread_create(&tids[3], NULL, SemThreadWorker, "4"); if (ret) {printf("Thread creation failed!!\n");exit(EXIT_FAILURE);}ret = pthread_create(&tids[4], NULL, SemThreadWorker, "5"); if (ret) {printf("Thread creation failed!!\n");exit(EXIT_FAILURE);}Sleep(100);printf("\n Post semaphore發(fā)送信號量過去: sem_post(&sem);\n");//for(int i=0;i<10;i++){// sem_post(&sem);// sem_post(&sem);// Sleep(100);//}if(sem_post(&sem)!=0){printf("Error sem_post ");}if(0==sem_getvalue(&sem,&ret)){printf("\n sem_getvalue value=%d \n",ret);}else{perror("@Error sem_getValue");}if(sem_post(&sem)!=0){printf("Error sem_post ");}if(0==sem_getvalue(&sem,&ret)){printf("\n sem_getvalue value=%d \n",ret);}else{perror("@Error sem_getValue");}if(sem_post_multiple(&sem,5)!=0){printf("Error sem_post_multiple ");}if(0==sem_getvalue(&sem,&ret)){printf("\n sem_getvalue value=%d \n",ret);}else{perror("@Error sem_getValue");}Sleep(2000);printf("\n sem_getvalue(&sem,&ret);\n");//sem_open//sem_close(&sem);//sem_unlinkif(0==sem_getvalue(&sem,&ret)){printf("\n sem_getvalue value=%d \n",ret);}else{perror("@Error sem_getValue");}//為了讓sem_wait全部停止阻塞,才可以destroysem_post_multiple(&sem,-ret);printf("\n sem_destroy(&sem);\n\n");//第一次 sem_destroy return 0if(sem_destroy(&sem)!=0){perror("@Error sem_destroy ");}//第二次 sem_destroy 多次 return -1if(sem_destroy(&sem)!=0){perror("@Error sem_destroy ");}if(sem_post(&sem)!=0){printf("@Error sem_post \n");}printf(" Wait for thread pthread_join synchronization...\n");void *threadResult=NULL;ret = pthread_join(tids[0], &threadResult); if (ret){printf("Thread join failed!!\n");exit(EXIT_FAILURE);}ret = pthread_join(tids[1], &threadResult); if (ret){printf("Thread join failed!!\n");exit(EXIT_FAILURE);}ret = pthread_join(tids[2], &threadResult); if (ret){printf("Thread join failed!!\n");exit(EXIT_FAILURE);}ret = pthread_join(tids[3], &threadResult); if (ret){printf("Thread join failed!!\n");exit(EXIT_FAILURE);}ret = pthread_join(tids[4], &threadResult); if (ret){printf("Thread join failed!!\n");exit(EXIT_FAILURE);}printf("press any key to continue...\n");//getchar(); _getch();return 1; }五個線程工作,用semaphore來管理隊列
總結(jié)
以上是生活随笔為你收集整理的pthread-win32 semaphore信号量总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: error while loading
- 下一篇: php用Simple Excel导出xl