1688網(wǎng)站上自己做模版專業(yè)營銷團(tuán)隊(duì)公司
15.信號燈(信號量)
Linux中的信號燈即信號量是一種用于進(jìn)程間同步或互斥的機(jī)制,它主要用于控制對共享資源的訪問。
在Linux系統(tǒng)中,信號燈作為一種進(jìn)程間通信(IPC)的方式,與其他如管道、FIFO或共享內(nèi)存等IPC方式不同,信號燈主要用于同步或互斥控制,以確保多個進(jìn)程之間能夠協(xié)調(diào)地訪問共享資源。信號燈可以看作是內(nèi)存中的一個標(biāo)志,進(jìn)程可以通過檢查信號燈的狀態(tài)來決定是否可以安全地訪問某些共享資源。
要點(diǎn)
- 創(chuàng)建和操作:要在Linux中使用信號燈,首先需要創(chuàng)建一個信號燈,并指定其初始值。對于二值信號燈,這個初始值通常是1,表示資源一開始是可用的。
- 等待和釋放:進(jìn)程可以執(zhí)行等待操作來測試信號燈的值,如果信號燈的值大于0,則進(jìn)程可以繼續(xù)執(zhí)行并將信號燈的值減1;如果值為0,則進(jìn)程必須等待直到信號燈的值變?yōu)檎龜?shù)。
- 共享資源控制:信號燈提供了一種機(jī)制,使得進(jìn)程能夠根據(jù)信號燈的狀態(tài)來判斷是否可以訪問某些共享資源。這類似于互斥鎖,確保了在任何時候只有一個進(jìn)程可以訪問臨界區(qū)。
- 進(jìn)程間通信:除了同步和互斥,信號燈還可以作為進(jìn)程間通信的一種方式。它們存在于內(nèi)核空間,與共享內(nèi)存和消息隊(duì)列一起構(gòu)成了Linux中主要的IPC通信方式。
- 有名信號燈: 可以通過路徑名在進(jìn)程間共享,因此不同進(jìn)程可以通過已知的路徑名來訪問同一個有名信號燈。 適用于需要在不同進(jìn)程間進(jìn)行同步的場景。
- 無名信號燈: 只能存在于內(nèi)存中,因此使用無名信號燈的進(jìn)程必須能夠訪問相同的內(nèi)存區(qū)域。通過共享內(nèi)存的方式創(chuàng)建,不依賴于文件系統(tǒng)中的路徑名。適用于單進(jìn)程內(nèi)多線程間的同步或在已經(jīng)映射相同內(nèi)存內(nèi)容的多個進(jìn)程之間的同步。
- System V信號燈:Linux支持System V的信號燈,這是一種傳統(tǒng)的信號燈實(shí)現(xiàn),用于在同一系統(tǒng)內(nèi)的進(jìn)程間進(jìn)行同步和互斥。
互斥和同步 是信號燈通常用于解決并發(fā)中的兩個主要問題:
-
互斥:確保當(dāng)一個進(jìn)程使用共享資源時,其他進(jìn)程不能同時訪問該資源。例如,打印設(shè)備只能由一個進(jìn)程使用,其他嘗試訪問打印設(shè)備的進(jìn)程必須等待,直到當(dāng)前進(jìn)程完成打印任務(wù)。
-
同步:確保進(jìn)程間的執(zhí)行順序符合特定的依賴關(guān)系。例如,一個進(jìn)程生成數(shù)據(jù),另一個進(jìn)程消費(fèi)這些數(shù)據(jù),消費(fèi)者進(jìn)程需要等待生產(chǎn)者進(jìn)程生成數(shù)據(jù)后才能繼續(xù)執(zhí)行。
PV操作
信號燈的工作原理基于PV操作,其中P操作用于請求資源(減少信號量的值),而V操作用于釋放資源(增加信號量的值)。
-
P操作“proberen”(嘗試):如果信號量的值為正,則將其減一,允許進(jìn)程繼續(xù)執(zhí)行。如果信號量的值為0或負(fù),則進(jìn)程被阻塞,直到信號量的值變?yōu)檎龜?shù)。
-
V操作“verhogen”(釋放):將信號量的值加一,如果有其他進(jìn)程因等待該信號量而被阻塞,則其中一個進(jìn)程會被喚醒。
POSIX是一組用于確保操作系統(tǒng)間可移植性的IEEE標(biāo)準(zhǔn),主要針對Unix系統(tǒng)。POSIX標(biāo)準(zhǔn)為操作系統(tǒng)提供了一套共通的規(guī)則,使得軟件開發(fā)更加高效,同時也讓用戶能夠在不同的系統(tǒng)之間無縫地遷移和運(yùn)行應(yīng)用程序。
有名信號燈
用到的函數(shù)主要有:
sem_open
有名信號燈打開sem_close
有名信號燈關(guān)閉sem_unlink
有名信號燈的刪除sem_wait
信號燈P操作,申請資源sem_post
信號燈V操作,釋放資源
sem_open 函數(shù)
原型:
#include <fcntl.h> #include <sys/stat.h> #include <semaphore.h> sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
功能:創(chuàng)建或打開一個有名信號量(named semaphore)的函數(shù)
參數(shù):
name
:信號量的名稱,用于標(biāo)識信號量。oflag
:打開選項(xiàng),可以是以下值的組合:
O_CREAT
:如果信號量不存在,則創(chuàng)建一個新的信號量。O_EXCL
:與O_CREAT
一起使用,表示如果信號量已存在,則返回錯誤。O_RDWR
:允許對信號量進(jìn)行讀寫操作。mode
:設(shè)置信號量的權(quán)限,通常設(shè)置為0644。value
:信號量的初始值。返回值:
- 成功時,返回一個指向信號量的指針。
- 失敗時,返回SEM_FAILURE(通常是NULL)。
sem_close 函數(shù)
原型:
#include <semaphore.h> int sem_close(sem_t *sem);
功能:用于關(guān)閉一個信號量的函數(shù)
參數(shù):
sem
:指向要關(guān)閉的信號量的指針返回值:
- 成功時,返回0。
- 失敗時,返回-1,并設(shè)置errno。
sem_unlink 函數(shù)
原型:
#include <semaphore.h> int sem_unlink(const char *name);
功能:刪除一個命名信號量
參數(shù):
name
:要刪除的信號量的名稱返回值:
- 成功時,返回0
- 失敗時,返回-1,并設(shè)置errno
sem_wait 函數(shù)
原型:
#include <semaphore.h> int sem_wait(sem_t *sem);
功能:”P操作“等待一個信號量。當(dāng)信號量的值大于0時,該函數(shù)會將信號量的值減1,并立即返回。如果信號量的值為0,則該函數(shù)會阻塞當(dāng)前線程,直到信號量的值大于0為止。
參數(shù):
sem
:指向要等待的信號量的指針。返回值:
- 成功時,返回0。
- 失敗時,返回-1,并設(shè)置errno。
sem_post 函數(shù)
原型:
#include <semaphore.h> int sem_post(sem_t *sem);
功能:”V操作“增加一個信號量的值。當(dāng)信號量的值大于0時,如果有其他線程正在等待該信號量,則
sem_post
函數(shù)會喚醒其中一個等待的線程。如果沒有線程在等待,那么信號量的值簡單地增加,它與sem_wait
函數(shù)相對應(yīng).參數(shù):
sem
:指向要操作的信號量的指針。返回值:
- 成功時,返回0。
- 失敗時,返回-1,并設(shè)置errno。
示例-有名信號燈使用
使用信號量和共享內(nèi)存實(shí)現(xiàn)的簡單進(jìn)程間通信(IPC)示例
一個簡單的命令行界面,用戶可以在命令行中輸入字符串,并將其存儲到共享內(nèi)存中。通過信號量來實(shí)現(xiàn)進(jìn)程間的同步,確保數(shù)據(jù)的讀寫操作不會發(fā)生沖突
tes_semw.c 寫程序
#include <fcntl.h> #include <sys/stat.h> #include <semaphore.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> #include <signal.h>void delsemfile(int sig) { sem_unlink("mysem_w"); // 刪除名為"mysem_w"的信號量 exit(0); // 退出程序 }int main() { sem_t *sem_r,*sem_w; // 定義兩個信號量指針,分別用于讀和寫操作 key_t key; // 定義鍵值,用于生成共享內(nèi)存標(biāo)識符 int shmid; // 定義共享內(nèi)存標(biāo)識符 char *shmaddr; // 定義共享內(nèi)存地址指針struct sigaction act; // 定義信號處理結(jié)構(gòu)體 act.sa_handler = delsemfile; // 設(shè)置信號處理函數(shù)為delsemfile act.sa_flags = 0; // 設(shè)置信號處理標(biāo)志為0 sigemptyset(&act.sa_mask); // 清空信號集sigaction(SIGINT,&act,NULL); // 注冊信號處理函數(shù),當(dāng)接收到SIGINT信號時調(diào)用delsemfile函數(shù)key = ftok(".",100); // 生成鍵值,用于創(chuàng)建共享內(nèi)存標(biāo)識符 if(key<0) {perror("ftok"); // 如果生成失敗,打印錯誤信息return 0; }shmid = shmget(key,500,0666|IPC_CREAT); // 創(chuàng)建共享內(nèi)存段,大小為500字節(jié),權(quán)限為0666,如果不存在則創(chuàng)建 if(shmid<0) {perror("shmget"); // 如果創(chuàng)建失敗,打印錯誤信息return 0; }shmaddr = shmat(shmid,NULL,0); // 將共享內(nèi)存段附加到進(jìn)程的地址空間,并獲取共享內(nèi)存地址指針sem_r = sem_open("mysem_r",O_CREAT|O_RDWR,0666,0); // 創(chuàng)建名為"mysem_r"的信號量,初始值為0 sem_w = sem_open("mysem_w",O_CREAT|O_RDWR,0666,1); // 創(chuàng)建名為"mysem_w"的信號量,初始值為1while(1) {sem_wait(sem_w); // 等待名為"mysem_w"的信號量變?yōu)榉橇阒?/span>printf(">"); // 輸出提示符">"fgets(shmaddr,500,stdin); // 從標(biāo)準(zhǔn)輸入讀取一行字符串,存儲到共享內(nèi)存中sem_post(sem_r); // 增加名為"mysem_r"的信號量的值,表示數(shù)據(jù)已寫入共享內(nèi)存 } }
tes_semr.c 讀程序
#include <fcntl.h> #include <sys/stat.h> #include <semaphore.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> #include <signal.h>void delsemfile(int sig) { sem_unlink("mysem_r"); // 刪除名為"mysem_r"的信號量 exit(0); // 退出程序 }int main(){sem_t *sem_r,*sem_w; // 定義兩個信號量指針,分別用于讀和寫操作 key_t key; // 定義鍵值,用于生成共享內(nèi)存標(biāo)識符 int shmid; // 定義共享內(nèi)存標(biāo)識符 char *shmaddr; // 定義共享內(nèi)存地址指針 struct sigaction act; // 定義信號處理結(jié)構(gòu)體 act.sa_handler = delsemfile; // 設(shè)置信號處理函數(shù)為delsemfile act.sa_flags = 0; // 設(shè)置信號處理標(biāo)志為0 sigemptyset(&act.sa_mask); // 清空信號集sigaction(SIGINT,&act,NULL); // 注冊信號處理函數(shù),當(dāng)接收到SIGINT信號時調(diào)用delsemfile函數(shù)key = ftok(".",100); // 生成鍵值,用于創(chuàng)建共享內(nèi)存標(biāo)識符 if(key<0) {perror("ftok"); // 如果生成失敗,打印錯誤信息return 0; }shmid = shmget(key,500,0666|IPC_CREAT); // 創(chuàng)建共享內(nèi)存段,大小為500字節(jié),權(quán)限為0666,如果不存在則創(chuàng)建 if(shmid<0) {perror("shmget"); // 如果創(chuàng)建失敗,打印錯誤信息return 0; }shmaddr = shmat(shmid,NULL,0); // 將共享內(nèi)存段附加到進(jìn)程的地址空間,并獲取共享內(nèi)存地址指針sem_r = sem_open("mysem_r",O_CREAT|O_RDWR,0666,0); // 創(chuàng)建名為"mysem_r"的信號量,初始值為0 sem_w = sem_open("mysem_w",O_CREAT|O_RDWR,0666,1); // 創(chuàng)建名為"mysem_w"的信號量,初始值為1while(1) {sem_wait(sem_r); // 等待名為"mysem_r"的信號量變?yōu)榉橇阒?/span>printf("%s\n",shmaddr); // 輸出共享內(nèi)存中的字符串sem_post(sem_w); // 增加名為"mysem_w"的信號量的值,表示數(shù)據(jù)已讀取完成 } }
運(yùn)行效果如圖,實(shí)現(xiàn)了兩個進(jìn)程通訊
可以通過命令
ls /dev/shm
查看信號量文件;在Linux系統(tǒng)中,/dev/shm目錄是用于存放共享內(nèi)存和信號量文件的特殊目錄
ctrl + c
退出程序后,捕獲到SIGINT
信號后執(zhí)行delsemfile()
刪除信號量文件
無名信號燈
用到的函數(shù)有:
sem_init
初始化無名信號量sem_destory
銷毀無名信號量sem_wait
信號燈P操作,申請資源sem_post
信號燈V操作,釋放資源
sem_init 函數(shù)
原型:
#include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:初始化一個無名信號量
參數(shù):
sem
:指向要初始化的信號量的指針。pshared
:指定信號量的類型,如果為0,則表示該信號量是進(jìn)程私有的;如果為非0值,則表示該信號量是進(jìn)程間共享的。value
:指定信號量的初始值。返回值:
- 成功時,返回0;
- 失敗時,返回-1,并設(shè)置
errno
。
sem_destory 函數(shù)
原型:
#include <semaphore.h> int sem_destroy(sem_t *sem);
功能:銷毀一個無名信號量
參數(shù):
sem
:指向要銷毀的信號量的指針。返回值:
- 成功時,返回0;
- 失敗時,返回-1,并設(shè)置
errno
。注意:只有當(dāng)信號量的引用計(jì)數(shù)變?yōu)?時,才能安全地銷毀它。如果還有其他線程或進(jìn)程正在等待該信號量,那么銷毀操作將失敗,并且
errno
將被設(shè)置為EBUSY
。在這種情況下,需要確保所有使用該信號量的線程或進(jìn)程都已經(jīng)結(jié)束,然后再嘗試銷毀它。
示例-無名信號燈使用
使用信號量和共享內(nèi)存實(shí)現(xiàn)的簡單進(jìn)程間通信(IPC)示例。主要功能是在一個進(jìn)程中輸入字符串,另一個進(jìn)程中讀取并打印這些字符串。
#include <fcntl.h> #include <sys/stat.h> #include <semaphore.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/ipc.h> #include <sys/shm.h> #include <signal.h> #include <pthread.h>sem_t sem_r,sem_w; // 定義兩個信號量,用于讀寫同步 char *shmaddr; // 共享內(nèi)存地址指針void destroysem(int sig) // 信號處理函數(shù),用于銷毀信號量并退出程序 { sem_destroy(&sem_r); // 銷毀讀信號量 sem_destroy(&sem_w); // 銷毀寫信號量 exit(0); // 退出程序 }void *readmem(void *arg) // 讀取共享內(nèi)存中的字符串并打印的線程函數(shù) { while(1) {sem_wait(&sem_r); // 等待讀信號量printf("%s\n",shmaddr); // 打印共享內(nèi)存中的字符串sem_post(&sem_w); // 釋放寫信號量 } }int main() { key_t key; // 鍵值 int shmid; // 共享內(nèi)存標(biāo)識符struct sigaction act; // 信號處理結(jié)構(gòu)體 act.sa_handler = destroysem; // 設(shè)置信號處理函數(shù) act.sa_flags = 0; // 設(shè)置信號處理標(biāo)志 sigemptyset(&act.sa_mask); // 清空信號集sigaction(SIGINT,&act,NULL); // 注冊信號處理函數(shù)key = ftok(".",100); // 生成鍵值 if(key<0) {perror("ftok"); // 輸出錯誤信息return 0; }shmid = shmget(key,500,0666|IPC_CREAT); // 創(chuàng)建共享內(nèi)存 if(shmid<0) {perror("shmget"); // 輸出錯誤信息return 0; }shmaddr = shmat(shmid,NULL,0); // 將共享內(nèi)存映射到進(jìn)程地址空間sem_init(&sem_r,0,0); // 初始化讀信號量,初始值為0 sem_init(&sem_w,0,1); // 初始化寫信號量,初始值為1pthread_t tid; // 線程標(biāo)識符 pthread_create(&tid,NULL,readmem,NULL); // 創(chuàng)建線程,執(zhí)行readmem函數(shù)while(1) {sem_wait(&sem_w); // 等待寫信號量printf(">"); // 提示用戶輸入fgets(shmaddr,500,stdin); // 從標(biāo)準(zhǔn)輸入讀取字符串并存儲到共享內(nèi)存中sem_post(&sem_r); // 釋放讀信號量 } }
運(yùn)行效果如圖
在父進(jìn)程中,它循環(huán)接收用戶輸入的數(shù)據(jù)并將其寫入共享內(nèi)存中。在子進(jìn)程中,它循環(huán)讀取共享內(nèi)存中的數(shù)據(jù)并打印出來。
System V 信號燈
System V 信號燈是一種用于進(jìn)程間同步和互斥的機(jī)制,它允許多個進(jìn)程共享資源而不會產(chǎn)生沖突。
- 信號燈集合:System V 信號燈可以是一個或多個計(jì)數(shù)信號燈的集合。這意味著可以同時操作集合中的任意多個信號燈,以協(xié)調(diào)進(jìn)程間的訪問順序。
- 信號燈操作:System V 信號燈的操作通常涉及三個步驟:初始化(創(chuàng)建)、P 操作(等待資源)和 V 操作(釋放資源)。P 操作用于請求資源,如果資源不可用則進(jìn)程將等待;V 操作用于釋放資源,使得其他等待該資源的進(jìn)程可以繼續(xù)執(zhí)行
- 避免死鎖:通過申請多個資源時使用 System V 信號燈,可以減少死鎖的風(fēng)險。死鎖是指兩個或多個進(jìn)程在互相等待對方釋放資源時無法繼續(xù)執(zhí)行的狀態(tài)。
System V 信號燈是一種重要的同步機(jī)制,它在多進(jìn)程編程中扮演著關(guān)鍵角色,確保了資源的有序訪問和數(shù)據(jù)的一致性。
用到的函數(shù)有:
semget
創(chuàng)建/打開信號燈semop
對信號燈集合中的信號量進(jìn)行P - V操作semctl
信號燈集合的控制(初始化/刪除)
semget 函數(shù)
原型:
#include <sys/sem.h> int semget(key_t key, int nsems, int semflg);
功能:獲取一個信號量集的標(biāo)識符
參數(shù):
key
:是一個鍵值,用于唯一標(biāo)識一個信號量集。通常使用ftok()
函數(shù)生成。nsems
:指定需要創(chuàng)建或獲取的信號量數(shù)量。semflg
:設(shè)置信號量集的訪問權(quán)限和創(chuàng)建標(biāo)志??梢允且韵轮档慕M合:
IPC_CREAT
:如果信號量集不存在,則創(chuàng)建一個新的信號量集。IPC_EXCL
:與IPC_CREAT
一起使用,表示如果信號量集已經(jīng)存在,則返回錯誤。0
:表示不設(shè)置任何特殊標(biāo)志。返回值:
- 如果成功,返回信號量集的標(biāo)識符(非負(fù)整數(shù))。
- 如果失敗,返回-1,并設(shè)置
errno
為相應(yīng)的錯誤碼。
semop 函數(shù)
原型:
#include <sys/sem.h> int semop(int semid, struct sembuf *sops, unsigned nsops);
功能:改變信號量的值,對信號燈集合中的信號量進(jìn)行P - V操作
參數(shù):
semid
:是一個信號量集的標(biāo)識符,由semget()
函數(shù)返回。sops
:是一個指向struct sembuf
結(jié)構(gòu)體數(shù)組的指針,該數(shù)組定義了要執(zhí)行的操作。nsops
:指定sops
數(shù)組中操作的數(shù)量。
struct sembuf
結(jié)構(gòu)體:struct sembuf {unsigned short sem_num; // 信號量編號short sem_op; // 操作類型short sem_flg; // 操作標(biāo)志 };
各個字段的含義如下:
sem_num
:指定要操作的信號量的編號。如果設(shè)置為0,則表示對整個信號量集進(jìn)行操作。sem_op
:指定要對信號量執(zhí)行的操作類型。
- 當(dāng)
sem_op
> 0,它表示進(jìn)程釋放控制的資源,即信號量的值將增加sem_op
的數(shù)量。- 當(dāng)
sem_op
= 0,如果沒有設(shè)置IPC_NOWAIT標(biāo)志,調(diào)用進(jìn)程將進(jìn)入睡眠狀態(tài)直到信號量的值為0;如果設(shè)置了該標(biāo)志且信號量值不為0,則進(jìn)程不會進(jìn)入睡眠,而是直接返回EAGAIN。- 當(dāng)
sem_op
< 0,它表示嘗試獲取資源使用權(quán),信號量的值將增加sem_op
的絕對值。如果此時信號量的值小于或等于sem_op
的絕對值,操作將會阻塞,直到信號量的值大于或等于sem_op
的絕對值。sem_flg
:指定操作的標(biāo)志。可以是以下值的組合:
IPC_NOWAIT
:非阻塞模式,如果無法立即執(zhí)行操作,則立即返回。SEM_UNDO
:撤銷之前的操作。0
:不設(shè)置任何特殊標(biāo)志。返回值:
- 如果成功,返回0。
- 如果失敗,返回-1,并設(shè)置
errno
為相應(yīng)的錯誤碼。
semctl 函數(shù)
原型:
#include <sys/sem.h> int semctl(int semid, int semnum, int cmd, ...);
功能:控制信號量集
參數(shù):
semid
:是一個信號量集的標(biāo)識符,由semget()
函數(shù)返回。semnum
:指定要操作的信號量的編號。如果設(shè)置為0,則表示對整個信號量集進(jìn)行操作。cmd
:指定要執(zhí)行的命令??梢允且韵轮抵?#xff1a;
IPC_RMID
:刪除信號量集。(常用)IPC_SET
:設(shè)置信號量集的屬性。(常用)IPC_STAT
:獲取信號量集的狀態(tài)信息。(常用)SETVAL
:設(shè)置信號燈的值,需要用到第四個參數(shù):共用體。(常用)IPC_INFO
:獲取系統(tǒng)支持的信號量集的最大數(shù)量和當(dāng)前使用的數(shù)量。SEM_STAT
:獲取指定信號量的狀態(tài)信息。GETALL
:獲取所有信號量的值。GETNCNT
:獲取等待某個信號量變?yōu)榉橇阒档倪M(jìn)程數(shù)。GETPID
:獲取最后一個操作指定信號量的進(jìn)程ID。GETVAL
:獲取指定信號量的值。GETZCNT
:獲取等待某個信號量變?yōu)榱阒档倪M(jìn)程數(shù)。SETALL
:設(shè)置所有信號量的值。...
:根據(jù)cmd
的不同,可能需要傳遞額外的參數(shù)。返回值:
- 如果成功,返回相應(yīng)的結(jié)果或狀態(tài)信息。
- 如果失敗,返回-1,并設(shè)置
errno
為相應(yīng)的錯誤碼
示例-System V信號燈使用
基于信號量和共享內(nèi)存的進(jìn)程間通信(IPC)示例。它創(chuàng)建了一個父子進(jìn)程,并使用信號量和共享內(nèi)存進(jìn)行數(shù)據(jù)傳遞。
#include <semaphore.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <sys/sem.h>#define SEM_READ 0 #define SEM_WRITE 1//semctl函數(shù)用到的參數(shù) union semun { int val; }; // P操作函數(shù),用于對信號量進(jìn)行減一操作 void Poperation(int semid,int semindex) { struct sembuf sbuf; sbuf.sem_num = semindex; sbuf.sem_op = -1; sbuf.sem_flg = 0;semop(semid,&sbuf,1); }// V操作函數(shù),用于對信號量進(jìn)行加一操作 void Voperation(int semid,int semindex) { struct sembuf sbuf; sbuf.sem_num = semindex; sbuf.sem_op = 1; sbuf.sem_flg = 0;semop(semid,&sbuf,1); }int main() { key_t key; // 定義鍵值key char *shmaddr; // 共享內(nèi)存地址指針 int semid,shmid; // 信號量和共享內(nèi)存的ID key = ftok(".",100); // 生成鍵值 if(key<0) {perror("ftok"); // 如果生成失敗,輸出錯誤信息return 0; }semid = semget(key,2,IPC_CREAT |0666); // 創(chuàng)建信號量集合 if(semid<0) {perror("semget"); // 如果創(chuàng)建失敗,輸出錯誤信息return 0; } shmid = shmget(key,500,IPC_CREAT |0666); // 創(chuàng)建共享內(nèi)存 shmaddr = shmat(shmid,NULL,0); // 將共享內(nèi)存映射到進(jìn)程地址空間 union semun mysem; // 定義信號量聯(lián)合體 mysem.val = 0; // 初始化讀信號量的值為0 semctl(semid,SEM_READ,SETVAL,mysem); // 設(shè)置讀信號量的值 mysem.val = 1; // 初始化寫信號量的值為1 semctl(semid,SEM_WRITE,SETVAL,mysem); // 設(shè)置寫信號量的值pid_t pid; // 定義進(jìn)程ID pid = fork(); // 創(chuàng)建子進(jìn)程 if(pid<0) {perror("fork"); // 如果創(chuàng)建失敗,輸出錯誤信息shmctl(shmid,IPC_RMID,NULL); // 刪除共享內(nèi)存semctl(semid,0,IPC_RMID); // 刪除信號量集合exit(-1); }else if(pid == 0) {// 子進(jìn)程循環(huán)讀取共享內(nèi)存中的數(shù)據(jù)并打印while(1){Poperation(semid,SEM_READ); // 對讀信號量進(jìn)行P操作printf("%s\n",shmaddr); // 打印共享內(nèi)存中的數(shù)據(jù)Voperation(semid,SEM_WRITE); // 對寫信號量進(jìn)行V操作} } else {// 父進(jìn)程循環(huán)接收用戶輸入的數(shù)據(jù)并寫入共享內(nèi)存while(1){Poperation(semid,SEM_WRITE); // 對寫信號量進(jìn)行P操作printf(">"); // 提示用戶輸入數(shù)據(jù)fgets(shmaddr,32,stdin); // 從標(biāo)準(zhǔn)輸入讀取數(shù)據(jù)并寫入共享內(nèi)存Voperation(semid,SEM_READ); // 對讀信號量進(jìn)行V操作} } }
運(yùn)行結(jié)果如圖
在父進(jìn)程中,它循環(huán)接收用戶輸入的數(shù)據(jù)并將其寫入共享內(nèi)存中。在子進(jìn)程中,它循環(huán)讀取共享內(nèi)存中的數(shù)據(jù)并打印出來。