swoole中信號量的用法是什么

swoole中,信號量主要用來保護共享資源,使得資源在一個時刻只有一個進程;信號量的值為正的時候,說明所測試的線程可以鎖定而使用,信號量的值若為0,則說明測試的線程要進入睡眠隊列中,等待被喚醒。

swoole中信號量的用法是什么

本教程操作環境:Windows10系統、Swoole4版、DELL G3電腦

swoole中信號量的用法是什么

信號量的使用主要是用來保護共享資源,使得資源在一個時刻只有一個進程(線程)

所擁有。信號量的值為正的時候,說明它空閑。所測試的線程可以鎖定而使用它。若為0,說明它被占用,測試的線程要進入睡眠隊列中,等待被喚醒。

linux提供兩種信號量:

(1)?內核信號量,由內核控制路徑使用

(2)?用戶態進程使用的信號量,這種信號量又分為POSIX信號量和SYSTEM

V信號量。

POSIX信號量又分為有名信號量和無名信號量。

有名信號量,其值保存在文件中,?所以它可以用于線程也可以用于進程間的同步。無名

信號量,其值保存在內存中。

內核信號量

內核信號量的構成

內核信號量類似于自旋鎖,因為當鎖關閉著時,它不允許內核控制路徑繼續進行。然而,

當內核控制路徑試圖獲取內核信號量鎖保護的忙資源時,相應的進程就被掛起。只有在資源被釋放時,進程才再次變為可運行。

只有可以睡眠的函數才能獲取內核信號量;中斷處理程序和可延遲函數都不能使用內

核信號量。

內核信號量是Struct?semaphore類型的對象,它在

#include?<pthread.h> #include?<semaphore.h> #include?<sys> #include?<stdio.h> #include?<unistd.h> int?number;?//?被保護的全局變量 sem_t?sem_id; void*?thread_one_fun(void?*arg) { sem_wait(&amp;sem_id); printf("thread_one?have?the?semaphoren"); number++; printf("number?=?%dn",number); sem_post(&amp;sem_id); } void*?thread_two_fun(void?*arg) { sem_wait(&amp;sem_id); printf("thread_two?have?the?semaphore?n"); number--; printf("number?=?%dn",number); sem_post(&amp;sem_id); } int?main(int?argc,char?*argv[]) { number?=?1; pthread_t?id1,?id2; sem_init(&amp;sem_id,?0,?1); pthread_create(&amp;id1,NULL,thread_one_fun,?NULL); pthread_create(&amp;id2,NULL,thread_two_fun,?NULL); pthread_join(id1,NULL); pthread_join(id2,NULL); printf("main,,,n"); return?0; }</unistd.h></stdio.h></sys></semaphore.h></pthread.h>

上面的例程,到底哪個線程先申請到信號量資源,這是隨機的。如果想要某個特定的順

序的話,可以用2個信號量來實現。例如下面的例程是線程1先執行完,然后線程2才繼

續執行,直至結束。

int?number;?//?被保護的全局變量 sem_t?sem_id1,?sem_id2; void*?thread_one_fun(void?*arg) { sem_wait(&amp;sem_id1); printf(“thread_one?have?the?semaphoren”); number++; printf(“number?=?%dn”,number); sem_post(&amp;sem_id2); } void*?thread_two_fun(void?*arg) { sem_wait(&amp;sem_id2); printf(“thread_two?have?the?semaphore?n”); number–; printf(“number?=?%dn”,number); sem_post(&amp;sem_id1); } int?main(int?argc,char?*argv[]) { number?=?1; pthread_t?id1,?id2; sem_init(&amp;sem_id1,?0,?1);?//?空閑的 sem_init(&amp;sem_id2,?0,?0);?//?忙的 pthread_create(&amp;id1,NULL,thread_one_fun,?NULL); pthread_create(&amp;id2,NULL,thread_two_fun,?NULL); pthread_join(id1,NULL); pthread_join(id2,NULL); printf(“main,,,n”); return?0; }

(b)無名信號量在相關進程間的同步

說是相關進程,是因為本程序中共有2個進程,其中一個是另外一個的子進程(由

fork

產生)的。

本來對于fork來說,子進程只繼承了父進程的代碼副本,mutex理應在父子進程

中是相互獨立的兩個變量,但由于在初始化mutex的時候,由pshared?=?1指

定了mutex處于共享內存區域,所以此時mutex變成了父子進程共享的一個變

量。此時,mutex就可以用來同步相關進程了。

#include?<semaphore.h> #include?<stdio.h> #include?<errno.h> #include?<stdlib.h> #include?<unistd.h> #include?<sys> #include?<sys> #include?<fcntl.h> #include?<sys> int?main(int?argc,?char?**argv) { int?fd,?i,count=0,nloop=10,zero=0,*ptr; sem_t?mutex; //open?a?file?and?map?it?into?memory fd?=?open("log.txt",O_RDWR|O_CREAT,S_IRWXU); write(fd,&amp;zero,sizeof(int)); ptr?=?mmap(?NULL,sizeof(int),PROT_READ?| PROT_WRITE,MAP_SHARED,fd,0?); close(fd); /*?create,?initialize?semaphore?*/ if(?sem_init(&amp;mutex,1,1)?<p><strong>2.有名信號量</strong></p> <p>有名信號量的特點是把信號量的值保存在文件中。</p> <p>這決定了它的用途非常廣:既可以用于線程,也可以用于相關進程間,甚至是不相關</p> <p>進程。</p> <p>(a)有名信號量能在進程間共享的原因</p> <p>由于有名信號量的值是保存在文件中的,所以對于相關進程來說,子進程是繼承了父</p> <p>進程的文件描述符,那么子進程所繼承的文件描述符所指向的文件是和父進程一樣的,當</p> <p>然文件里面保存的有名信號量值就共享了。</p> <p>(b)有名信號量相關函數說明</p> <p>有名信號量在使用的時候,和無名信號量共享sem_wait和sem_post函數。</p> <p>區別是有名信號量使用sem_open代替sem_init,另外在結束的時候要像關閉文件</p> <p>一樣去關閉這個有名信號量。</p> <p>(1)打開一個已存在的有名信號量,或創建并初始化一個有名信號量。一個單一的調用就完</p> <p>成了信號量的創建、初始化和權限的設置。</p> <p>sem_t?*sem_open(const?char?*name,?int?oflag,?mode_t?mode?,?int?value);</p> <p>name是文件的路徑名;</p> <p>Oflag?有O_CREAT或O_CREAT|EXCL兩個取值;</p> <p>mode_t控制新的信號量的訪問權限;</p> <p>Value指定信號量的初始化值。</p> <p>注意:</p> <p>這里的name不能寫成/tmp/aaa.sem這樣的格式,因為在linux下,sem都是創建</p> <p>在/dev/shm目錄下。你可以將name寫成“/mysem”或“mysem”,創建出來的文件都</p> <p>是“/dev/shm/sem.mysem”,千萬不要寫路徑。也千萬不要寫“/tmp/mysem”之類的。</p> <p>當oflag?=?O_CREAT時,若name指定的信號量不存在時,則會創建一個,而且后</p> <p>面的mode和value參數必須有效。若name指定的信號量已存在,則直接打開該信號量,</p> <p>同時忽略mode和value參數。</p> <p>當oflag?=?O_CREAT|O_EXCL時,若name指定的信號量已存在,該函數會直接返</p> <p>回Error。</p> <p>(2)?一旦你使用了信號量,銷毀它們就變得很重要。</p> <p>在做這個之前,要確定所有對這個有名信號量的引用都已經通過sem_close()函數</p> <p>關閉了,然后只需在退出或是退出處理函數中調用sem_unlink()去刪除系統中的信號量,</p> <p>注意如果有任何的處理器或是線程引用這個信號量,sem_unlink()函數不會起到任何的作</p> <p>用。</p> <p>也就是說,必須是最后一個使用該信號量的進程來執行sem_unlick才有效。因為每個</p> <p>信號燈有一個引用計數器記錄當前的打開次數,sem_unlink必須等待這個數為0時才能把</p> <p>name所指的信號燈從文件系統中刪除。也就是要等待最后一個sem_close發生。</p> <p>(c)有名信號量在無相關進程間的同步</p> <p>前面已經說過,有名信號量是位于共享內存區的,那么它要保護的資源也必須是位于</p> <p>共享內存區,只有這樣才能被無相關的進程所共享。</p> <p>在下面這個例子中,服務進程和客戶進程都使用shmget和shmat來獲取得一塊共享內</p> <p>存資源。然后利用有名信號量來對這塊共享內存資源進行互斥保護。</p> <pre class="brush:php;toolbar:false">File1:?server.c #include?<sys> #include?<sys> #include?<sys> #include?<stdio.h> #include?<semaphore.h> #include?<sys> #include?<sys> #include?<fcntl.h> #define?SHMSZ?27 char?SEM_NAME[]=?"vik"; int?main() { char?ch; int?shmid; key_t?key; char?*shm,*s; sem_t?*mutex; //name?the?shared?memory?segment key?=?1000; //create?&amp;?initialize?semaphore mutex?=?sem_open(SEM_NAME,O_CREAT,0644,1); if(mutex?==?SEM_FAILED) { perror("unable?to?create?semaphore"); sem_unlink(SEM_NAME); exit(-1); } //create?the?shared?memory?segment?with?this?key shmid?=?shmget(key,SHMSZ,IPC_CREAT|0666); if(shmidFile?2:?client.c #include?<sys> #include?<sys> #include?<sys> #include?<stdio.h> #include?<semaphore.h> #include?<sys> #include?<sys> #include?<fcntl.h> #define?SHMSZ?27 char?SEM_NAME[]=?"vik"; int?main() { char?ch; int?shmid; key_t?key; char?*shm,*s; sem_t?*mutex; //name?the?shared?memory?segment key?=?1000; //create?&amp;?initialize?existing?semaphore mutex?=?sem_open(SEM_NAME,0,0644,0); if(mutex?==?SEM_FAILED) { perror("reader:unable?to?execute?semaphore"); sem_close(mutex); exit(-1); } //create?the?shared?memory?segment?with?this?key shmid?=?shmget(key,SHMSZ,0666); if(shmid<p>SYSTEM?V信號量</p> <p>這是信號量值的集合,而不是單個信號量。相關的信號量操作函數由</p> <pre class="brush:php;toolbar:false">#include?<sys> #include?<sys> #include?<sys> #include?<stdio.h> static?int?nsems; static?int?semflg; static?int?semid; int?errno=0; union?semun?{ int?val; struct?semid_ds?*buf; unsigned?short?*array; }arg; int?main() { struct?sembuf?sops[2];?//要用到兩個信號量,所以要定義兩個操作數組 int?rslt; unsigned?short?argarray[80]; arg.array?=?argarray; semid?=?semget(IPC_PRIVATE,?2,?0666); if(semid?<p>推薦學習: <a href="https://www.php.cn/swoole/" target="_blank">swoole教程</a></p></stdio.h></sys></sys></sys>

? 版權聲明
THE END
喜歡就支持一下吧
點贊9 分享