您好,登錄后才能下訂單哦!
一.信號量
信號量是一種數據操作鎖,本身不具有數據交換功能,而是通過控制其他的通信資源來實現進程之間的通信,簡單來講,信號量相當于一個計數器,計數當前某種資源的個數。信號量的周期也是隨內核的。為了解決多個程序同時訪問一個共享資源引發的問題。
臨界資源:多個進程能訪問到的公共資源。
臨界區:將能訪問帶臨界資源的代碼成為臨界區。
同步:對臨界資源的訪問具有順序性。
pv 操作:
p(sv) sv>0 減1 sv=0 掛起的該進程執行
s(sv) 沒有進程因等待sv而掛起就加1,有進程等待sv被掛起,就恢復運行。
信號量用到的函數:
int semget(key_t key,int nsems,int smflag)//nsems:信號量個數
以信號量集為基本單位進行申請。
int semctl(int semid, int semnum, int cmd, ...);//semnum:第幾個信號量
struct sembuf
{
unsigned short sem_num;
short sem_op;
short sem_flg;
}
第一個成員,sem_num,是信號量數目,通常為0,除非我們正在使用一個信號量數組。sem_op成員是信號量的變化量值。(我們可以以任何量改變信 號量值,而不只是1)通常情況下中使用兩個值,-1是我們的P操作,用來等待一個信號量變得可用,而+1是我們的V操作,用來通知一個信號量可用。
最后一個成員,sem_flg,通常設置為SEM_UNDO。這會使得操作系統跟蹤當前進程對信號量所做的改變,而且如果進程終止而沒有釋放這個信號量, 如果信號量為這個進程所占有,這個標記可以使得操作系統自動釋放這個信號量。將sem_flg設置為SEM_UNDO是一個好習慣,除非我們需要不同的行為。如果我們確實變我們需要一個不同的值而不是SEM_UNDO,一致性是十分重要的,否則我們就會變得十分迷惑,當我們的進程退出時,內核是否會嘗試清理我們的信號量。
semnu 的聯合體,初始化信號量的時候用得到:
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
信號量實現進程間通信:
//comm.h 1 2 #pragma once 3 #include<unistd.h> 4 #include<stdlib.h> 5 #include<stdio.h> 6 #include<sys/types.h> 7 #include<sys/sem.h> 8 #include<sys/ipc.h> 9 #define _PATH_ "." 10 #define _PROJ_ID_ 0x7777 11 12 union semun 13 { 14 int val; 15 struct semid_ds *buf; 16 unsigned short *array; 17 struct seminfo *_buf; 18 }; 19 static int comm(int __sem_nums,int flag); 20 int create_sem_set(int _sem_nums); 21 int get_sem_set(int _sem_nums); 22 int init_sem_set(int _sem_id,int _sem_num,int _sem_val); 23 int p_sem_elem(int _sem_id ,int _sem_num); 24 int v_sem_elem(int _sem_id,int _sem_num); 25 int destroy_sem(int _sem_id); ~ //comm.c 1 #include"comm.h" 2 static int comm(int _sem_nums,int flag) 3 { 4 key_t key=ftok(_PATH_,_PROJ_ID_); 5 if(key<0) 6 { 7 perror("ftok"); 8 return -1; 9 } 10 int sem_id=semget(key,_sem_nums,flag); 11 if(sem_id<0) 12 { 13 perror("semget"); 14 return -1; 15 } 16 17 return sem_id; 18 19 } 20 int create_sem_set(int _sem_nums) 21 { 22 int flag=IPC_CREAT|IPC_EXCL|0666; 23 return comm(_sem_nums,flag); 24 25 26 } 27 int get_sem_set(int _sem_nums) 28 { 29 int flag=IPC_CREAT; 30 return comm(_sem_nums,flag); 31 } 32 int init_sem_set(int _sem_id,int _sem_num,int _sem_val) 33 { 34 union semun _un; 35 _un.val=_sem_val; 36 if(semctl(_sem_id,_sem_num,SETVAL,_un)<0) 37 { 38 perror("semctl"); 39 return -1; 40 41 } 42 return 0; 43 } 44 int p_sem_elem(int _sem_id ,int _sem_num) 45 { 46 struct sembuf _sem_buf[1]; 47 _sem_buf[0].sem_num=_sem_num; 48 _sem_buf[0].sem_op=-1; 49 _sem_buf[0].sem_flg=0; 50 if(semop(_sem_id,_sem_buf,1)<0) 51 { 52 perror("semop"); 53 return -1; 54 55 } 56 return 0; 57 } 58 int v_sem_elem(int _sem_id,int _sem_num) 59 { 60 struct sembuf _sem_buf[1]; 61 _sem_buf[0].sem_num=_sem_num; 62 _sem_buf[0].sem_op=1; 63 _sem_buf[0].sem_flg=0; 64 if(semop(_sem_id,_sem_buf,1)<0) 65 { 66 perror("semop"); 67 return -1; 68 69 } 70 return 0; 71 } 74 int destroy_sem(int _sem_id) 75 { 76 if(semctl(_sem_id,0,IPC_RMID,NULL)<0) 77 { 78 perror("semctl"); 79 return -1; 80 81 82 } 83 return 0; } 91 int main() 92 { 93 int sem_id=create_sem_set(1); 94 init_sem_set(sem_id,0,1); 95 pid_t pid=fork(); 96 if(pid<0) 97 { 98 perror("fork"); 99 exit(1); 100 } 101 102 else if(pid==0) 103 { 104 int sem_id=get_sem_set(1); 105 while(1) 106 { 107 p_sem_elem(sem_id,0); 108 printf("A"); 109 sleep(1); 110 fflush(stdout); 111 printf("A"); 112 sleep(7); 113 fflush(stdout); 114 v_sem_elem(sem_id,0); 116 } 117 } 118 119 else 120 { 121 while(1) 122 { 123 p_sem_elem(sem_id,0); 124 125 printf("B"); 126 sleep(2); 127 fflush(stdout); 128 printf("B"); 129 sleep(5); 130 fflush(stdout); 131 v_sem_elem(sem_id,0); 132 133 134 } 135 } return 0; }
程序運行結果:
總結:
上述程序中顯示器就相當于公共資源,父子進程都想要訪問,在其上面輸出自己的內容,就必須使用信號量,這樣就防止了兩個同時輸出引發的問題,兩個進程只能一個訪問完,另一個在訪問。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。