版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、信號量.什么是信號量信號量的使用主要是用來保護共享資源,使得資源在一個時刻只有一個進程(線程)所擁有。信號量的值為正的時候,說明它空閑。所測試的線程可以鎖定而使用它。若為0,說明它被占用,測試的線程要進入睡眠隊列中,等待被喚醒。.信號量的分類在學(xué)習(xí)信號量之前,我們必須先知道一一Linux提供兩種信號量:(1) 內(nèi)核信號量,由內(nèi)核控制路徑使用(2) 用戶態(tài)進程使用的信號量,這種信號量又分為POSIX信號量和SYSTEM V信口曰.號量。POSIX信號量又分為有名信號量和無名信號量。有名信號量,其值保存在文件中,所以它可以用于線程也可以用于進程間的同步。無名信號量,其值保存在內(nèi)存中。倘若對信號量沒
2、有以上的全面認識的話,你就會很快發(fā)現(xiàn)自己在信號量的森林里迷失了方向。內(nèi)核信號量1.內(nèi)核信號量的構(gòu)成內(nèi)核信號量類似于自旋鎖, 因為當(dāng)鎖關(guān)閉著時,它不允許內(nèi)核控制路徑繼續(xù)進行。 然而, 當(dāng)內(nèi)核控制路徑試圖獲取內(nèi)核信號量鎖保護的忙資源時,相應(yīng)的進程就被掛起。 只有在資源被釋放時,進程才再次變?yōu)榭蛇\行。只有可以睡眠的函數(shù)才能獲取內(nèi)核信號量;中斷處理程序和可延遲函數(shù)都不能使用內(nèi)核/亠口 曰. 信號量。內(nèi)核信號量是 struct semaphore類型的對象,它在 <asm/semaphore.h>中定義: struct semaphore atomiccount;int sleepers;
3、wait_queue_head_t wait;cou nt :相當(dāng)于信號量的值,大于0,資源空閑;等于 0,資源忙,但沒有進程等待這個保護的資源;小于 0,資源不可用,并至少有一個進程等待資源。wait :存放等待隊列鏈表的地址,當(dāng)前等待資源的所有睡眠進程都會放在這個鏈表中。 sleepers:存放一個標(biāo)志,表示是否有一些進程在信號量上睡眠。2 .內(nèi)核信號量中的等待隊列(刪除,沒有聯(lián)系)上面已經(jīng)提到了內(nèi)核信號量使用了等待隊列wait_queue來實現(xiàn)阻塞操作。當(dāng)某任務(wù)由于沒有某種條件沒有得到滿足時,它就被掛到等待隊列中睡眠。 當(dāng)條件得到滿足時,該任務(wù)就被移出等待隊列,此時并不意味著該任務(wù)就被馬
4、上執(zhí)行,因為它又被移進工作隊列中等待CPU資源,在適當(dāng)?shù)臅r機被調(diào)度。內(nèi)核信號量是在內(nèi)部使用等待隊列的,也就是說該等待隊列對用戶是隱藏的,無須用戶干涉。由用戶真正使用的等待隊列我們將在另外的篇章進行詳解。3 .內(nèi)核信號量的相關(guān)函數(shù)(1 )初始化:void sema_ in it (struct semaphore *sem, int val);void init_MUTEX (struct semaphore *sem);將 sem 的值置為 1,表示資源空閑void init MUTEX LOCKED (struct semaphore *sem);將 sem 的值置為 0,表示資源忙(2)
5、申請內(nèi)核信號量所保護的資源:void down(struct semaphore * sem);/ 可弓I起睡眠int down_interruptible(struct semaphore * sem); / down_interruptible 能被信號打斷int down_trylock(struct semaphore * sem);非阻塞函數(shù),不會睡眠。無法鎖定資源則馬上返回(3) 釋放內(nèi)核信號量所保護的資源:void up(struct semaphore * sem);4 .內(nèi)核信號量的使用例程在驅(qū)動程序中,當(dāng)多個線程同時訪問相同的資源時(驅(qū)動中的全局變量時一種典型的共享資源),
6、可能會引發(fā)“競態(tài)“,因此我們必須對共享資源進行并發(fā)控制。Linux內(nèi)核中解決并發(fā)控制的最常用方法是自旋鎖與信號量(絕大多數(shù)時候作為互斥鎖使用)。ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off)/獲得信號量if (dow n_in terruptible( &sem)return - ERESTARTSYS;將用戶空間的數(shù)據(jù)復(fù)制到內(nèi)核空間的global_varif (copy_from_user(&global_var, buf, sizeof( in t)up
7、(&sem); return - EFAULT;/釋放信號量up(&sem);retur n sizeof( in t);四. POSIX 信號量與 SYSTEM V 信號量的比較1. 對POSIX來說,信號量是個非負整數(shù)。常用于線程間同步。而SYSTEM V信號量則是一個或多個信號量的集合,它對應(yīng)的是一個信號量結(jié)構(gòu)體, 這個結(jié)構(gòu)體是為 SYSTEM V IPC服務(wù)的,信號量只不過是它的一部分。常用于進程間同步。2. POSIX信號量的引用頭文件是“ <semaphore.h>”,而SYSTEM V信號量的引用頭文件是 “<sys/sem.h> ”。3
8、.從使用的角度,System V信號量是復(fù)雜的,而 Posix信號量是簡單。比如, POSIX 信號量的創(chuàng)建和初始化或PV操作就很非常方便。五. POSIX信號量詳解1 無名信號量無名信號量的創(chuàng)建就像聲明一般的變量一樣簡單,例如:sem_t sem_id。然后再初始化該無名信號量,之后就可以放心使用了。無名信號量常用于多線程間的同步,同時也用于相關(guān)進程間的同步。 也就是說,無名信號量必須是多個進程(線程)的共享變量,無名信號量要保護的變量也必須是多個進程(線程)的共享變量,這兩個條件是缺一不可的。常見的無名信號量相關(guān)函數(shù):sem destroyint sem_ in it(sem_t *sem
9、, int pshared, un sig ned int value);1)pshared=0用于同一多線程的同步;2)若pshared>0用于多個相關(guān)進程間的同步(即由 fork產(chǎn)生的) int sem_getvalue(sem_t *sem, int *sval);取回信號量sem的當(dāng)前值,把該值保存到sval中。若有1個或更多的線程或進程調(diào)用sem_wait阻塞在該信號量上,該函數(shù)返回兩種值:1) 返回02) 返回阻塞在該信號量上的進程或線程數(shù)目linux米用返回的第一種策略。sem_wait( 或sem_trywait) 相當(dāng)于P操作,即申請資源。int sem_wait(se
10、m_t *sem);/ 這是一個阻塞的函數(shù)測試所指定信號量的值,它的操作是原子的。若sem>0,那么它減1并立即返回。若sem=0 ,則睡眠直到 sem>0 ,此時立即減1,然后返回。int sem_trywait(sem_t *sem);/ 非阻塞的函數(shù)其他的行為和sem_wait 一樣,除了:若sem=0 ,不是睡眠,而是返回一個錯誤EAGAIN 。sem post 相當(dāng)于V操作,釋放資源。int sem_post(sem_t *sem);把指定的信號量sem的值加1;呼醒正在等待該信號量的任意線程。注意:在這些函數(shù)中,只有 sem_post 是信號安全的函數(shù),它是可重入函數(shù)(
11、a) 無名信號量在多線程間的同步無名信號量的常見用法是將要保護的變量放在sem_wait 和sem_post 中間所形成的臨界區(qū)內(nèi),這樣該變量就會被保護起來,例如:#i nclude <pthread.h>#in clude <semaphore.h>#in clude <sys/types.h>#i nclude <stdio.h>#in clude <uni std.h>int number;/被保護的全局變量sem_t sem_id;void* thread_one_fun(void *arg)sem_wait(&sem
12、d);prin tf("thread one have the semaphore' n");nu mber+; printf("nu mber = %dn ”, nu mber); sem_post(&sem_id);void* thread_two_fu n(void *arg)sem_wait(&semd);prin tf("thread_two have the semaphore n");nu mber-;printf("nu mber = %dn ”, nu mber); sem_post(&
13、;sem_id);int main (i nt argc,char *argv)nu mber = 1;pthread_t id1, id2;semnit(&semd, 0, 1);pthread_create(&id1,NULL,thread_o ne_fun, NULL); pthread_create(&id2,NULL,thread_two_fu n, NULL); pthreadoi n( id1,NULL);pthreadoi n( id2,NULL);prin tf("mai n, ,n"); return 0;上面的例程,到底哪個線程
14、先申請到信號量資源,這是隨機的。如果想要某個特定的順序的話,可以用 2個信號量來實現(xiàn)。例如下面的例程是線程1先執(zhí)行完,然后線程 2才繼續(xù)執(zhí)行,直至結(jié)束。int number;/被保護的全局變量sem_t sem_id1, sem_id2;void* thread_one_fun(void *arg)sem_wait(&sem_id1);prin tf("thread_ one have the semaphoren");nu mber+;printf("nu mber = %dn ”, nu mber); sem_post(&sem_id2);vo
15、id* thread_two_fu n(void *arg)sem_wait(&sem_id2);prin tf("thread_two have the semaphore n");nu mber-;printf("nu mber = %dn ”, nu mber); sem_post(&semd1);int main (i nt argc,char *argv)nu mber = 1;pthread_t id1, id2;semn it(&sem_id1,0, 1);/ 空閑的semn it(&sem_id2, 0, 0);/
16、忙的pthread_create(&id1,NULL,thread_o ne_fun, NULL); pthread_create(&id2,NULL,thread_two_fu n, NULL); pthreadoi n( id1,NULL);pthreadoi n( id2,NULL);prin tf("mai n, ,n");return 0;(b) 無名信號量在相關(guān)進程間的同步說是相關(guān)進程,是因為本程序中共有 2個進程,其中一個是另外一個的子進程(由fork產(chǎn)生)的。本來對于fork來說,子進程只繼承了父進程的代碼副本,mutex理應(yīng)在父子進程中是相
17、互獨立的兩個變量,但由于在初始化mutex的時候,由pshared = 1指定了mutex處于共享內(nèi)存區(qū)域,所以此時 mutex變成了父子進程共享的一個變量。此 時,mutex就可以用來同步相關(guān)進程了。#in clude <semaphore.h>#i nclude <stdio.h>#i nclude verrno .h>#i nclude <stdlib.h>#i nclude <uni std.h>#i nclude <sys/types.h>#i nclude <sys/stat.h>#in clude &l
18、t;fcn tl.h>#i nclude <sys/mma n.h>int main (i nt argc, char *argv)int fd, i,cou nt=0, nloop=10,zero=0,*ptr;sem t mutex;/open a file and map it into memoryfd = ope n("log.txt",O_RDWR|O_CREAT,SRWXU); write(fd, &zero,sizeof(i nt);ptr = mmap( NULL,sizeof(i nt),PROT_READ |PROT_WRIT
19、E,MAP_SHARED,fd,O ); close(fd);/* create, initialize semaphore */ if( semnit(&mutex,1,1) < 0) /perror("semaphore in itilizatio n"); exit(0);if (fork() = 0) /* child process*/for (i = 0; i < nlo op; i+)sem_wait(&m utex);prin tf("child: %dn", (*ptr)+); sem_post(&m
20、 utex); exit(0);/* back to pare nt process */ for (i = 0; i < nlo op; i+) sem_wait(&m utex);printf("parent: %dn", (*ptr)+); sem_post(&m utex); _exit(0);2 .有名信號量有名信號量的特點是把信號量的值保存在文件中。甚至是不相關(guān)進這決定了它的用途非常廣:既可以用于線程,也可以用于相關(guān)進程間, 程。(a)有名信號量能在進程間共享的原因由于有名信號量的值是保存在文件中的,所以對于相關(guān)進程來說, 子進程是繼承了父
21、進當(dāng)然文程的文件描述符,那么子進程所繼承的文件描述符所指向的文件是和父進程一樣的, 件里面保存的有名信號量值就共享了。(b) 有名信號量相關(guān)函數(shù)說明有名信號量在使用的時候,和無名信號量共享sem_wait 和sem_post 函數(shù)。區(qū)別是有名信號量使用sem_open 代替sem_init,另外在結(jié)束的時候要像關(guān)閉文件一樣去關(guān)閉這個有名信號量。(1)打開一個已存在的有名信號量,或創(chuàng)建并初始化一個有名信號量。一個單一的調(diào)用就完 成了信號量的創(chuàng)建、初始化和權(quán)限的設(shè)置。sem_t *sem_ope n(const char *n ame, int oflag, mode_t mode , int v
22、alue);name是文件的路徑名;Oflag 有 O_CREAT 或 O_CREAT|EXCL 兩個取值;mode_t控制新的信號量的訪問權(quán)限;Value指定信號量的初始化值。這里的name不能寫成/tmp/aaa.sem這樣的格式,因為在linux下,sem 都是創(chuàng)建在/dev/shm目錄下。你可以將 name寫成"/mysem ”或"mysem ”,創(chuàng)建出來的文件都是"/dev/shm/sem.mysem ”,千萬不要寫路徑。也千萬不要寫"/tmp/mysem ”之類的。當(dāng)oflag = O_CREAT 時,若name指定的信號量不存在時,則會創(chuàng)建
23、一個,而且后 面的mode和value參數(shù)必須有效。若name指定的信號量已存在,則直接打開該信號量, 同時忽略 mode 和value 參數(shù)。當(dāng)oflag = O_CREAT|O_EXCL 時,若name指定的信號量已存在,該函數(shù)會直接返 回 error 。(2) 一旦你使用了一信號量,銷毀它們就變得很重要。在做這個之前,要確定所有對這個有名信號量的引用都已經(jīng)通過sem_close ()函數(shù)關(guān)閉了,然后只需在退出或是退出處理函數(shù)中調(diào)用sem_u nlin k()去刪除系統(tǒng)中的信號量,注意如果有任何的處理器或是線程引用這個信號量,sem_u nlin k()函數(shù)不會起到任何的作用。也就是說,必
24、須是最后一個使用該信號量的進程來執(zhí)行sem_u nlick 才有效。因為每個信號燈有一個引用計數(shù)器記錄當(dāng)前的打開次數(shù),sem_unlink必須等待這個數(shù)為 0時才能把name所指的信號燈從文件系統(tǒng)中刪除。也就是要等待最后一個sem_close發(fā)生。(c) 有名信號量在無相關(guān)進程間的同步前面已經(jīng)說過,有名信號量是位于共享內(nèi)存區(qū)的,那么它要保護的資源也必須是位于共享內(nèi)存區(qū),只有這樣才能被無相關(guān)的進程所共享。在下面這個例子中,服務(wù)進程和客戶進程都使用shmget和shmat來獲取得一塊共享內(nèi)存資源。然后利用有名信號量來對這塊共享內(nèi)存資源進行互斥保護。<u>File1: server.c
25、</u>#i nclude <sys/types.h>#i nclude <sys/ipc.h>#i nclude <sys/shm.h>#i nclude <stdio.h>#in clude <semaphore.h>#i nclude <sys/types.h>#i nclude <sys/stat.h>#in clude vfcn tl.h>#defi ne SHMSZ 27char SEM_NAME= "vik"int main()char ch;int shmi
26、d;key_t key;char *shm,*s;sem_t *mutex;n ame the shared memory segme nt key = 1OOO;/create & in itialize semaphoremutex = sem_ope n(SEM_NAME,O_CREAT,0644,1); if(mutex = SEM_FAILED)perror(" un able to create semaphore"); sem_u nlin k(SEM_NAME);exit(-1);/create the shared memory segme nt
27、with this key shmid = shmget(key,SHMS Z, IPC_CREAT|0666); if(shmid<0)perror("failure in shmget"); exit(-1);/attach this segme nt to virtual memory shm = shmat(shmid,NULL,0);/start writi ng into memorys = shm;for(ch='A'ch<='Z'ch+)sem_wait(mutex);*s+ = ch;sem_post(mutex
28、); _/the below loop could be replaced by binary semaphore while(*shm != '*')sleep(1);sem_close(mutex);sem_u nlin k(SEM_NAME);shmctl(shmid, IPC_RMID, 0);exit(0);<u>File 2: clie nt.c</u>#i nclude <sys/types.h>#i nclude <sys/ipc.h>#i nclude <sys/shm.h>#i nclude <
29、;stdio.h>#in clude <semaphore.h>#i nclude <sys/types.h>#i nclude <sys/stat.h>#in clude vfcn tl.h>#defi ne SHMSZ 27char SEM_NAME= "vik"int main()char ch;int shmid;key_t key;char *shm,*s;sem_t *mutex;n ame the shared memory segme ntkey = 1000;/create & in itialize
30、 exist ing semaphoremutex = sem_ope n(SEM_NAME,0,0644,0);if(mutex = SEM_FAILED)perror("reader:u nable to execute semaphore"); sem_close(mutex);exit(-1);/create the shared memory segme nt with this keyshmid = shmget(key,SHMS Z,0666);if(shmid<0)perror("reader:failure in shmget")
31、; exit(-1);/attach this segme nt to virtual memoryshm = shmat(shmid,NULL,0);/start read ings = shm;for(s=shm;*s!=NULL;s+)sem_wait(mutex); putchar(*s);sem_post(mutex); _/once done sig nal exit ing of reader:This can be replaced by ano ther semaphore*shm = '*'sem_close(mutex);shmctl(shmid, IPC
32、_RMID, 0);exit(0);六.SYSTEM V信號量這是信號量值的集合,而不是單個信號量。相關(guān)的信號量操作函數(shù)由<sys/ipc.h>引用。1 .信號量結(jié)構(gòu)體內(nèi)核為每個信號量集維護一個信號量結(jié)構(gòu)體,可在<sys/sem.h>找到該定義:struct semid_ds struct ipc_perm sem_perm; struct sem *sem_base;ushort sem_ nsems;time_t sem_otime;time_t sem_ctime;/*信號量集的操作許可權(quán)限*/*某個信號量sem結(jié)構(gòu)數(shù)組的指針,當(dāng)前信號量集中的每個信號量對應(yīng)其中一
33、個數(shù)組元素*/* sem_base數(shù)組的個數(shù) */*最后一次成功修改信號量數(shù)組的時間*/*成功創(chuàng)建時間 */struct sem ushort semval; short sempid;ushort semncnt; ushort semzc nt;/*信號量的當(dāng)前值*/*最后一次返回該信號量的進程ID號*/*等待semval大于當(dāng)前值的進程個數(shù)*/*等待semval變成0的進程個數(shù)*/;2 .常見的 SYSTEM V 信號量函數(shù)(a)關(guān)鍵字和描述符SYSTEM V信號量是SYSTEM V IPC (即SYSTEM V進程間通信)的組成部分,其他 的有SYSTEM V消息隊列,SYSTEM V
34、共享內(nèi)存。而關(guān)鍵字和 IPC描述符無疑是它們的共 同點,也使用它們,就不得不先對它們進行熟悉。這里只對SYSTEM V信號量進行討論。IPC描述符相當(dāng)于引用ID號,要想使用SYSTEM V信號量(或 MSG、SHM ),就必須 用IPC描述符來調(diào)用信號量。 而IPC描述符是內(nèi)核動態(tài)提供的 (通過semget來獲取),用戶 無法讓服務(wù)器和客戶事先認可共同使用哪個描述符,所以有時候就需要到關(guān)鍵字KEY來定位描述符。某個KEY只會固定對應(yīng)一個描述符(這項轉(zhuǎn)換工作由內(nèi)核完成),這樣假如服務(wù)器和客戶事先認可共同使用某個KEY,那么大家就都能定位到同一個描述符,也就能定位到同一個信號量,這樣就達到了SYS
35、TEM V信號量在進程間共享的目的。(b)創(chuàng)建和打開信號量int semget(key_t key, int nsems, int oflag)(1) nsems>0 :創(chuàng)建一個信的信號量集,指定集合中信號量的數(shù)量,一旦創(chuàng)建就不能更改。 nsems=0 :訪問一個已存在的集合 返回的是一個稱為信號量標(biāo)識符的整數(shù),semop和semctl函數(shù)將使用它。(4)創(chuàng)建成功后信號量結(jié)構(gòu)被設(shè)置:.sem_perm的uid和gid成員被設(shè)置成的調(diào)用進程的有效用戶ID和有效組ID.oflag參數(shù)中的讀寫權(quán)限位存入 sem_perm.mode.sem_otime被置為O,sem_ctime被設(shè)置為當(dāng)前時間
36、.sem_nsems被置為nsems參數(shù)的值該集合中的每個信號量不初始化,這些結(jié)構(gòu)是在semctl,用參數(shù) SET_VAL, SETALL初始化的。semget函數(shù)執(zhí)行成功后,就產(chǎn)生了一個由內(nèi)核維持的類型為 semid_ds結(jié)構(gòu)體的信號量 集,返回semid就是指向該信號量集的引索。(c)關(guān)鍵字的獲取有多種方法使客戶機和服務(wù)器在同一IPC結(jié)構(gòu)上會合:(1)服務(wù)器可以指定關(guān)鍵字IPC_PRIVATE創(chuàng)建一個新IPC結(jié)構(gòu),將返回的標(biāo)識符存放在某處(例如一個文件)以便客戶機取用。關(guān)鍵字IPC_PRIVATE保證服務(wù)器創(chuàng)建一個新 IPC結(jié)構(gòu)。這種技術(shù)的缺點是:服務(wù)器要將整型標(biāo)識符寫到文件中,然后客戶機
37、在此后又要讀文件取得此標(biāo)識符。IPC_PRIVATE關(guān)鍵字也可用于父、子關(guān)系進程。父進程指定IPC_PRIVATE創(chuàng)建一個新IPC結(jié)構(gòu),所返回的標(biāo)識符在 fork后可由子進程使用。子進程可將此標(biāo)識符作為exec函數(shù)的一個參數(shù)傳給一個新程序。(2)在一個公用頭文件中定義一個客戶機和服務(wù)器都認可的關(guān)鍵字。然后服務(wù)器指定此關(guān)鍵字創(chuàng)建一個新的IPC結(jié)構(gòu)。這種方法的問題是該關(guān)鍵字可能已與一個IPC結(jié)構(gòu)相結(jié)合,在此情況下,get函數(shù)(msgget、semget或shmget)出錯返回。服務(wù)器必須處理這一錯誤,刪 除已存在的IPC結(jié)構(gòu),然后試著再創(chuàng)建它。當(dāng)然,這個關(guān)鍵字不能被別的程序所占用。(3)客戶機和服
38、務(wù)器認同一個路徑名和課題I D (課題I D是0 2 5 5之間的字符值),然后調(diào)用函數(shù)ftok將這兩個值變換為一個關(guān)鍵字。這樣就避免了使用一個已被占用的關(guān)鍵字的問題。使用ftok并非高枕無憂。有這樣一種例外:服務(wù)器使用ftok獲取得一個關(guān)鍵字后,該文件就被刪除了,然后重建。此時客戶端以此重建后的文件來ftok所獲取的關(guān)鍵字就和服務(wù)器的關(guān)鍵字不一樣了。所以一般商用的軟件都不怎么用ftok。一般來說,客戶機和服務(wù)器至少共享一個頭文件,所以一個比較簡單的方法是避免使用ftok,而只是在該頭文件中存放一個大家都知道的關(guān)鍵字。(d)設(shè)置信號量的值(PV操作)int semop(i ntsemid, s
39、truct sembuf *opsptr, size_t n ops);(1) semid :是semget返回的semid(2)opsptr:指向信號量操作結(jié)構(gòu)數(shù)組(3) nops :opsptr所指向的數(shù)組中的 sembuf結(jié)構(gòu)體的個數(shù)struct sembuf short sem_num;/要操作的信號量在信號量集里的編號,short sem_op;/ 信號量操作short sem_flg;/操作表示符; 若sem_op是正數(shù),其值就加到 semval上,即釋放信號量控制的資源若sem_op是0,那么調(diào)用者希望等到 semval變?yōu)?,如果semval是0就返回;若sem_op是負數(shù),那
40、么調(diào)用者希望等待semval變?yōu)榇笥诨虻扔?sem_op的絕對值例如,當(dāng)前 semval為2,而sem_op = -3,那么怎么辦?注意:semval是指semid_ds中的信號量集中的某個信號量的值(5) sem_flgSEM_UNDO由進程自動釋放信號量IPC_NOWAIT不阻塞到這里,讀者肯定有個疑惑:semop希望改變的semval到底在哪里?我們怎么沒看到有它的痕跡?其實,前面已經(jīng)說明了,當(dāng)使用semget時,就產(chǎn)生了一個由內(nèi)核維護的信號量集(當(dāng)然每個信號量值即 semval也是只由內(nèi)核才能看得到了),用戶能看到的就是返回的 semido內(nèi)核通過semop函數(shù)的參數(shù),知道應(yīng)該去改變s
41、emid所指向的信號量的哪個 semval。(e)對信號集實行控制操作(semval的賦值等)int semctl(int semid, int semum, int cmd, ./* union semun arg */);semid是信號量集合;semnum是信號在集合中的序號; semum是一個必須由用戶自定義的結(jié)構(gòu)體,在這里我們務(wù)必弄清楚該結(jié)構(gòu)體的組成:union sem unint val;/ cmd = SETV ALstruct semid_ds *buf/ cmd = IPC_SET 或者 cmd = IPC_STATushort *array;/ cmd = SETALL,或
42、 cmd = GETALL;val只有cmd =SETV AL時才有用,此時指定的semval = arg.val。注意:當(dāng)cmd = GETVAL時,semctl函數(shù)返回的值就是我們想要的semvalo千萬不要以為指定的semval被返回到 arg.val中。array指向一個數(shù)組,當(dāng)cmd=SETALL時,就根據(jù)arg.array來將信號量集的所有值都 賦值;當(dāng)cmd =GETALL時,就將信號量集的所有值返回到arg.array指定的數(shù)組中。buf指針只在cmd=IPC_STAT或IPC_SET時有用,作用是 semid所指向的信號量集 (semid_ds機構(gòu)體)。一般情況下不常用,這里
43、不做談?wù)摗A硗?,cmd = IPC_RMID 還是比較有用的。(f)例碼#in elude <sys/types.h>#in elude <sys/ipc.h>#i nclude <sys/sem.h>#i nclude <stdio.h>static intn sems;static int semflg;static int semid;int errno=0;union sem un int val;struct semid_ds *buf;un sig ned short *array;arg;int mai n()struct semb
44、uf sops2; /要用到兩個信號量,所以要定義兩個操作數(shù)組 int rslt;un sig ned short argarray80;arg.array = argarray;semid = semget(IPC_PRIV ATE, 2, 0666);if(semid < 0 )prin tf("semget failed.errno: %dn", errno);exit(0);/獲取0th信號量的原始值rslt = semctl(semid, 0, GETV AL);prin tf("val = %dn",rslt);初始化0th信號量,然后
45、再讀取,檢查初始化有沒有成功arg.val = 1; /同一時間只允許一個占有者semctl(semid, 0, SETVAL, arg);rslt = semctl(semid, 0, GETV AL);prin tf("val = %dn",rslt);sops0.sem_ num = 0;sops0.sem op = -1;sops0.sem_flg = 0; sops1.sem_ num = 1;sops1.sem_op = 1;sops1.sem_flg = 0;rslt=semop(semid, sops, 1); / 申請 Oth 信號量,嘗試鎖定if (rs
46、lt < 0 )printf("semop failed.errno: %dn", errno);exit(0);可以在這里對資源進行鎖定sops0.sem_op = 1;semop(semid, sops, 1); /釋放 0th 信號量rslt = semctl(semid, 0, GETV AL);prin tf("val = %dn",rslt);rslt=semctl(semid, 0, GETALL, arg);if (rslt < 0)printf("semctl failed.errno: %dn", errno);exit(0);prin tf("val1:%dval2: %dn",(un sig ned in t)argarray0,( un sig ned in t)argarray1);if(semctl(semid, 1, IPC_RMID) = -1)Perror( semctl failure while clearing reaso
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 委托代售合同范本
- 茶桌購買合同范本
- 廣告購置合同范本
- 托管品牌合同范本
- 新風(fēng)機合同范本
- 人防開挖合同范本
- 意向種植合同范本
- 新版長期承包合同范本
- 出售電器合同范本
- 補充質(zhì)保合同范本
- 百度投訴保證函
- 2.7-植被與自然環(huán)境的關(guān)系(精品課件)-2020-2021學(xué)年高一地理(新教材中圖版必修第一冊)
- 清欠工作管理制度管理辦法
- 三甲評審文件盒資料--終稿
- 鐵路項目橋梁墩臺身施工方案
- 工作崗位風(fēng)險評估工作規(guī)程
- 智能存包柜(儲物柜)產(chǎn)品技術(shù)說明書
- 常見化學(xué)式大全
- 電鍍技術(shù)資料大全
- 偏拉墻體配筋分析及建議課件
- 消防電氣檢驗批質(zhì)量驗收記錄表(共18頁)
評論
0/150
提交評論