Linux下進(jìn)程通訊之信號(hào)量集
1.簡(jiǎn)介
?信號(hào)量集,就是由多個(gè)信號(hào)量組成的一個(gè)數(shù)組。 作為一個(gè)整體, 信號(hào)量集中所有的信號(hào)量使用同一個(gè)等待隊(duì)列。 Linux 的信號(hào)量集為進(jìn)程請(qǐng)求多個(gè)資源創(chuàng)造了條件。 Linux 規(guī)定, 當(dāng)進(jìn)程的一個(gè)操作需要多個(gè)共享資源時(shí), 如果只成功獲得了其中部分資源, 那么這個(gè)請(qǐng)求即告失敗, 進(jìn)程必須立即釋放所有已獲得資源, 已防止形成死鎖。
信號(hào)量本質(zhì)是一個(gè)計(jì)數(shù)器(不設(shè)置全局變量是因?yàn)檫M(jìn)程間是相互獨(dú)立的), 用于多進(jìn)程對(duì)共享數(shù)據(jù)對(duì)象的讀取, 它和管道有所不同, 它不以傳送數(shù)據(jù)為主要目 錄, 主要是用來(lái)保護(hù)共享資源(信號(hào)量也屬于臨界資源), 使得資源在同一時(shí)刻只能由一個(gè)進(jìn)程獨(dú)享。
2.工作原理
信號(hào)量只能進(jìn)行等待和發(fā)送信號(hào)兩種操作, 即 P(申請(qǐng))和 V(釋放)。
(1) P(申請(qǐng)):如果 SV 的值大于 0, 就給他減 1, 如果它的值為 0, 就掛起進(jìn)程。
(2) V(釋放):如果有其他進(jìn)程等待信號(hào)量而被掛起, 就讓他恢復(fù)運(yùn)行, 如果沒(méi)有進(jìn)程因等待信號(hào)量而掛起, 就給他加 1。
在信號(hào)量進(jìn)程 PV 操作時(shí)都是為了原子操作(原子操作:單指令的操作, 單條指令的執(zhí)行時(shí)不會(huì)被打斷的)。
3. 二值信號(hào)量
?? 二元信號(hào)量(Binary Semaphore)是最簡(jiǎn)單的一種鎖(互斥鎖), 它只有兩種狀態(tài):占用與非占用。 所以它的引 用計(jì)數(shù)為 1。
4. 查看系統(tǒng)信號(hào)量命令
??1.查看信號(hào)量組:ipcs -s
[wbyq@wbyq 0414work]$ ipcs -s
--------- 信號(hào)量數(shù)組 -----------
鍵 semid 擁有者 權(quán)限 nsems
0xd2350092 3 wbyq 666 1
??2.查看信號(hào)量限制信息:ipcs -ls
[wbyq@wbyq 0414work]$ ipcs -ls
--------- 信號(hào)量限制 -----------
最大數(shù)組數(shù)量 = 32000
每個(gè)數(shù)組的最大信號(hào)量數(shù)目 = 32000
系統(tǒng)最大信號(hào)量數(shù) = 1024000000
每次信號(hào)量調(diào)用最大操作數(shù) = 500
信號(hào)量最大值=32767
??3.查看信號(hào)量詳細(xì)信息:ipcs -s -i
[wbyq@wbyq 0414work]$ ipcs -s -i 3
信號(hào)量數(shù)組 semid=3
uid=1000 gid=1000 cuid=1000 cgid=1000
模式=0666,訪問(wèn)權(quán)限=0666
nsems = 1
otime = Fri Apr 29 10:27:21 2022
ctime = Fri Apr 29 10:25:28 2022
semnum 值 ncount zcount pid
0 1 0 0 13747
??4.創(chuàng)建信號(hào)量:ipcmk -S <信號(hào)量個(gè)數(shù)>
//創(chuàng)建信號(hào)量,信號(hào)量個(gè)數(shù)為5個(gè)
[wbyq@wbyq 0414work]$ ipcmk -S 5
信號(hào)量 id:6
//查看創(chuàng)建的信號(hào)量
[wbyq@wbyq 0414work]$ ipcs -s -i 6
信號(hào)量數(shù)組 semid=6
uid=1000 gid=1000 cuid=1000 cgid=1000
模式=0644,訪問(wèn)權(quán)限=0644
nsems = 5
otime = 未設(shè)置
ctime = Fri Apr 29 14:17:16 2022
semnum 值 ncount zcount pid
0 0 0 0 0
1 0 0 0 0
2 0 0 0 0
3 0 0 0 0
4 0 0 0 0
??5.刪除信號(hào)量:ipcrm -s
//刪除信號(hào)量6
[wbyq@wbyq 0414work]$ ipcs -s 6
--------- 信號(hào)量數(shù)組 -----------
鍵 semid 擁有者 權(quán)限 nsems
0xd2350092 3 wbyq 666 1
0xa8132e52 4 wbyq 644 1
0x9416e553 6 wbyq 644 5
[wbyq@wbyq 0414work]$ ipcrm -s 6
//刪除后結(jié)果
[wbyq@wbyq 0414work]$ ipcs -s
--------- 信號(hào)量數(shù)組 -----------
鍵 semid 擁有者 權(quán)限 nsems
0xd2350092 3 wbyq 666 1
0xa8132e52 4 wbyq 644 1
5.信號(hào)量相關(guān)函數(shù)
#include
#include
#include
int semget(key_t key, int nsems, int semflg);
函數(shù)功能:創(chuàng)建信號(hào)量
形參:key ?鍵值,ftok產(chǎn)生
???nsems?信號(hào)量個(gè)數(shù),幾乎總是為1
? ? ?semflg?標(biāo)志 IPC_CREAT|0666
返回值:失敗返回-1,成功返回semid
int semctl(int semid, int semnum, int cmd, …);
函數(shù)功能:信號(hào)量控制函數(shù)
形參:semid?semget函數(shù)返回值
???semnum?信號(hào)量數(shù)組下標(biāo),semnum=0表示第一個(gè)信號(hào)量
???cmd?控制命令:SETVAL 初始化信號(hào)量值
???????????IPC_RMID 刪除信號(hào)量,刪除只需要前三個(gè)參數(shù)即可
???????????GETVAL 獲取信號(hào)量值
???可變參數(shù)共用體類型(需要自己定義):
??????union semun {
?????????int val; /* 要設(shè)置的初始值 */
?????????struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
?????????unsigned short *array; /* Array for GETALL, SETALL */
?????????struct seminfo __buf; /* Buffer for IPC_INFO(Linux-specific) */
?????????};
返回值:失敗返回-1,成功根據(jù)cmd值返回
int semop(int semid, struct sembuf *sops, size_t nsops);
函數(shù)功能: 使用或者釋放信號(hào)量pv操作
形參:semid?semget函數(shù)返回值
???sops?信號(hào)量pv操作結(jié)構(gòu)體
????struct sembuf sops
????{
?????unsigned short sem_num; /* 信號(hào)量集下標(biāo),0表示第一個(gè)信號(hào)量 */
?????short sem_op; /*>0則v操作,釋放信號(hào)量
???????????<0則p操作,使用信號(hào)量*/
?????short sem_flg; / 0 表示默認(rèn)操作,沒(méi)有信號(hào)量可用就等待。IPC_NOWAIT 表示不等待。 */
????}
返回值:成功返回信號(hào)量標(biāo)志符,失敗返回-1;
6.創(chuàng)建一個(gè)信號(hào)量示例
??(1)創(chuàng)建信號(hào)量
#include
#include
#include
#include
#include
#include
#include
union semun
{
int val; /* 信號(hào)量值 */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};
int main(int argc,char *argv[])
{
if(argc!=2)
{
printf("格式:./a.out <信號(hào)量值>\n");
return 0;
}
key_t key=ftok("semget.c",1234);//產(chǎn)生鍵值
if(key==-1)
{
printf("產(chǎn)生鍵值失敗res=%s\n",strerror(errno));
return 0;
}
printf("key=%#x\n",key);
int semid=semget(key,1,IPC_CREAT|0666);//創(chuàng)建1個(gè)信號(hào)量
if(semid==-1)
{
printf("創(chuàng)建信號(hào)量集失敗res=%s\n",strerror(errno));
return 0;
}
printf("semid=%d\n",semid);
union semun sem;
sem.val=atoi(argv[1]);
/*初始化信號(hào)量*/
if(semctl(semid,0,SETVAL,sem))
{
printf("初始化信號(hào)量值失敗err=%s\n",strerror(errno));
return 0;
}
/*獲取信號(hào)量*/
int val=semctl(semid,0,GETVAL,NULL);
printf("信號(hào)量值:%d\n",val);
/*通過(guò)系統(tǒng)命令查看信號(hào)量詳細(xì)信息*/
char buff[20];
snprintf(buff,sizeof(buff),"ipcs -s -i %d",semid);
system(buff);
return 0;
}
??(2)使用信號(hào)量
#include
#include
#include
#include
#include
#include
#include
union semun
{
int val; /* 信號(hào)量值 */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};
int main(int argc,char *argv[])
{
if(argc!=2)
{
printf("格式:./a.out <使用信號(hào)值>\n");
return 0;
}
key_t key=ftok("semget.c",1234);//產(chǎn)生鍵值
if(key==-1)
{
printf("產(chǎn)生鍵值失敗res=%s\n",strerror(errno));
return 0;
}
printf("key=%#x\n",key);
int semid=semget(key,1,IPC_CREAT|0666);//創(chuàng)建1個(gè)信號(hào)量
if(semid==-1)
{
printf("創(chuàng)建信號(hào)量集失敗res=%s\n",strerror(errno));
return 0;
}
printf("semid=%d\n",semid);
/*獲取信號(hào)量*/
int val=semctl(semid,0,GETVAL,NULL);
printf("信號(hào)量值:%d\n",val);
/*pv操作*/
struct sembuf sops=
{
.sem_num=0,//信號(hào)量下標(biāo)
.sem_op=atoi(argv[1]),
.sem_flg=0//阻塞等待
};
int ret=semop(semid,&sops,1);
printf("ret=%d\n",ret);
/*獲取信號(hào)量*/
val=semctl(semid,0,GETVAL,NULL);
printf("信號(hào)量值:%d\n",val);
return 0;
}
7.創(chuàng)建多個(gè)信號(hào)量
??(1)創(chuàng)建多個(gè)信號(hào)量
#include
#include
#include
#include
#include
#include
#include
union semun
{
int val; /* 信號(hào)量值 */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};
int main(int argc,char *argv[])
{
if(argc!=4)
{
printf("格式:./a.out <信號(hào)量值1> <信號(hào)量值2> <信號(hào)量值3>\n");
return 0;
}
key_t key=ftok("semget.c",1234);//產(chǎn)生鍵值
if(key==-1)
{
printf("產(chǎn)生鍵值失敗res=%s\n",strerror(errno));
return 0;
}
printf("key=%#x\n",key);
int semid=semget(key,3,IPC_CREAT|0666);//創(chuàng)建3個(gè)信號(hào)量
if(semid==-1)
{
printf("創(chuàng)建信號(hào)量集失敗res=%s\n",strerror(errno));
return 0;
}
printf("semid=%d\n",semid);
union semun sem[3];
sem[0].val=atoi(argv[1]);//初始化第一個(gè)信號(hào)量
sem[1].val=atoi(argv[2]);//初始化第二個(gè)信號(hào)量
sem[2].val=atoi(argv[3]);//初始化第三個(gè)信號(hào)量
int i=0;
for(i=0;i<3;i++)
{
/*初始化信號(hào)量*/
if(semctl(semid,i,SETVAL,sem[i]))
{
printf("初始化信號(hào)量值失敗err=%s\n",strerror(errno));
return 0;
}
/*獲取信號(hào)量*/
int val=semctl(semid,i,GETVAL,NULL);
printf("第%d個(gè)信號(hào)量值:%d\n",i,val);
}
/*通過(guò)系統(tǒng)命令查看信號(hào)量詳細(xì)信息*/
system("ipcs -s");
return 0;
}
??(2)使用多個(gè)信號(hào)量
#include
#include
#include
#include
#include
#include
#include
union semun
{
int val; /* 信號(hào)量值 */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */
};
int main(int argc,char *argv[])
{
if(argc!=2)
{
printf("格式:./a.out <使用信號(hào)值>\n");
return 0;
}
key_t key=ftok("semget.c",1234);//產(chǎn)生鍵值
if(key==-1)
{
printf("產(chǎn)生鍵值失敗res=%s\n",strerror(errno));
return 0;
}
printf("key=%#x\n",key);
int semid=semget(key,3,IPC_CREAT|0666);//創(chuàng)建3個(gè)信號(hào)量
if(semid==-1)
{
printf("創(chuàng)建信號(hào)量集失敗res=%s\n",strerror(errno));
return 0;
}
printf("semid=%d\n",semid);
int i=0;
/*獲取信號(hào)量*/
for(i=0;i<3;i++)
{
/*獲取信號(hào)量*/
int val=semctl(semid,i,GETVAL,NULL);
printf("第%d個(gè)信號(hào)量值:%d\n",i,val);
}
/*pv操作*/
struct sembuf sops[3]=
{
{
.sem_num=0,//信號(hào)量下標(biāo)
.sem_op=atoi(argv[1]),
.sem_flg=0//阻塞等待
},
{
.sem_num=1,//信號(hào)量下標(biāo)
.sem_op=atoi(argv[1]),
.sem_flg=0//阻塞等待
},
{
.sem_num=2,//信號(hào)量下標(biāo)
.sem_op=atoi(argv[1]),
.sem_flg=0//阻塞等待
}
};
int ret=semop(semid,sops,3);//一次使用3個(gè)信號(hào)量
printf("ret=%d\n",ret);
/*獲取信號(hào)量*/
/*獲取信號(hào)量*/
for(i=0;i<3;i++)
{
/*獲取信號(hào)量*/
int val=semctl(semid,i,GETVAL,NULL);
printf("第%d個(gè)信號(hào)量值:%d\n",i,val);
}
return 0;
}
??(3)運(yùn)行效果
-
Linux
+關(guān)注
關(guān)注
87文章
11212瀏覽量
208721 -
IPC
+關(guān)注
關(guān)注
3文章
337瀏覽量
51772 -
進(jìn)程
+關(guān)注
關(guān)注
0文章
201瀏覽量
13938
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論