0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Linux下進(jìn)程通訊之信號(hào)量集

嵌入式技術(shù) ? 來(lái)源:嵌入式技術(shù) ? 作者:嵌入式技術(shù) ? 2022-08-19 19:55 ? 次閱讀

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)行, 如果沒有進(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)操作,沒有信號(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;
}
pYYBAGL_eEaAH_D3AAKPgdfERdw629.png#pic_center

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)行效果

poYBAGL_eEeAB3BeAAJ-UvQXGSQ340.png#pic_center

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11161

    瀏覽量

    208459
  • IPC
    IPC
    +關(guān)注

    關(guān)注

    3

    文章

    335

    瀏覽量

    51712
  • 進(jìn)程
    +關(guān)注

    關(guān)注

    0

    文章

    198

    瀏覽量

    13933
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    FreeRTOS信號(hào)量使用教程

    信號(hào)量是操作系統(tǒng)中重要的一部分,信號(hào)量一般用來(lái)進(jìn)行資源管理和任務(wù)同步, FreeRTOS中信號(hào)量又分為二值信號(hào)量、 計(jì)數(shù)型信號(hào)量、互斥
    的頭像 發(fā)表于 12-19 09:22 ?2991次閱讀
    FreeRTOS<b class='flag-5'>信號(hào)量</b>使用教程

    linux操作系統(tǒng)進(jìn)程通信設(shè)計(jì)

    用戶進(jìn)程。我們可以從頭文件/usr/src/linux/include/linux/sem.h中看到內(nèi)核用來(lái)維護(hù)信號(hào)量狀態(tài)的各個(gè)結(jié)構(gòu)的定義。信號(hào)量
    發(fā)表于 04-16 09:17

    進(jìn)程間通信 信號(hào)量

    定義:信號(hào)量是一個(gè)計(jì)數(shù)器,用于多進(jìn)程對(duì)共享數(shù)據(jù)對(duì)象的存取訪問(wèn)控制。為了獲得共享資源,進(jìn)程需要執(zhí)行下列操作信號(hào)量使用步驟:1:初始化信號(hào)量--
    發(fā)表于 07-20 10:15

    關(guān)于ucosii中信號(hào)量的問(wèn)題

    我定義了一個(gè)信號(hào)量: OS_FLAG_GRP *FlagTest1;INT8U Flag_Error在任務(wù)初始化之前,創(chuàng)建:FlagTest1=OSFlagCreate((OS_FLAGS)0
    發(fā)表于 10-19 16:49

    芯靈思SinlinxA33開發(fā)板的Linux內(nèi)核信號(hào)量學(xué)習(xí)

    用戶進(jìn)程。我們可以從頭文件/usr/src/linux/include/linux/sem.h 中看到內(nèi)核用來(lái)維護(hù)信號(hào)量狀態(tài)的各個(gè)結(jié)構(gòu)的定義。信號(hào)量
    發(fā)表于 02-20 15:50

    芯靈思SinlinxA64開發(fā)板 Linux內(nèi)核信號(hào)量學(xué)習(xí)

    信號(hào)量狀態(tài)的各個(gè)結(jié)構(gòu)的定義。信號(hào)量是一個(gè)數(shù)據(jù)集合,用戶可以單獨(dú)使用這一合的每個(gè)元素。要調(diào)用的第一個(gè)函數(shù)是semget,用以獲得一個(gè)信號(hào)量ID。Li
    發(fā)表于 03-15 16:10

    linux多線程編程中,一次等待多個(gè)信號(hào)量怎么解決

    linux多線程(非進(jìn)程)編程中,一次等待多個(gè)信號(hào)量怎么解決?并且等到信號(hào)量來(lái)了后,能判斷是那一個(gè)?功能如同window
    發(fā)表于 06-17 05:55

    你了解Linux 各類信號(hào)量?

    內(nèi)核信號(hào)量與用戶信號(hào)量,用戶信號(hào)量分為POXIS信號(hào)量和SYSTEMV信號(hào)量,POXIS信號(hào)量
    發(fā)表于 05-04 17:19 ?2464次閱讀
    你了解<b class='flag-5'>Linux</b> 各類<b class='flag-5'>信號(hào)量</b>?

    Linux IPC POSIX 信號(hào)量

    //獲得信號(hào)量sem的當(dāng)前的值,放到sval中。如果有線程正在block這個(gè)信號(hào)量,sval可能返回兩個(gè)值,0或“-正在block的線程的數(shù)目”,Linux返回0//成功返回0,失敗返回-1設(shè)
    發(fā)表于 05-16 17:39 ?900次閱讀

    Linux IPC System V 信號(hào)量

    ?立即銷毀指定的信號(hào)量,調(diào)用的進(jìn)程的的effective UID必須和信號(hào)量的創(chuàng)建者或所有者相匹配,或者這個(gè)
    發(fā)表于 04-02 14:46 ?301次閱讀

    Linux 多線程信號(hào)量同步

    直到系統(tǒng)將資源分配給該進(jìn)程(進(jìn)入等待隊(duì)列,一直等到資源輪到該進(jìn)程)。V操作:如果在該信號(hào)量的等待隊(duì)列中有進(jìn)程在等待資源,則喚醒一個(gè)阻塞進(jìn)程;
    發(fā)表于 04-02 14:47 ?368次閱讀

    Linux信號(hào)量(2):POSIX 信號(hào)量

    上一章,講述了 SYSTEM V 信號(hào)量,主要運(yùn)行于進(jìn)程之間,本章主要介紹 POSIX 信號(hào)量:有名信號(hào)量、無(wú)名信號(hào)量。 POSIX
    的頭像 發(fā)表于 10-29 17:34 ?648次閱讀

    LINUX內(nèi)核的信號(hào)量設(shè)計(jì)與實(shí)現(xiàn)

    控制路徑可以睡眠。我們從 LINUX內(nèi)核信號(hào)量最直觀的設(shè)計(jì)/實(shí)現(xiàn)出發(fā),通過(guò)一步步改進(jìn),揭示在x86平臺(tái)上完整的信號(hào)量設(shè)計(jì)/實(shí)現(xiàn),然后探討在不同平臺(tái)上通用的信號(hào)量設(shè)計(jì)/實(shí)現(xiàn)。
    發(fā)表于 01-14 16:55 ?18次下載

    LINUX內(nèi)核的信號(hào)量設(shè)計(jì)與實(shí)現(xiàn)

    控制路徑可以睡眠。我們從 LINUX內(nèi)核信號(hào)量最直觀的設(shè)計(jì)/實(shí)現(xiàn)出發(fā),通過(guò)一步步改進(jìn),揭示在x86平臺(tái)上完整的信號(hào)量設(shè)計(jì)/實(shí)現(xiàn),然后探討在不同平臺(tái)上通用的信號(hào)量設(shè)計(jì)/實(shí)現(xiàn)。
    發(fā)表于 01-14 16:55 ?5次下載

    使用Linux信號(hào)量實(shí)現(xiàn)互斥點(diǎn)燈

    信號(hào)量常用于控制對(duì)共享資源的訪問(wèn),有計(jì)數(shù)型信號(hào)量和二值信號(hào)量之分。初始化時(shí)信號(hào)量值大于1的,就是計(jì)數(shù)型信號(hào)量,計(jì)數(shù)型
    的頭像 發(fā)表于 04-13 15:12 ?747次閱讀
    使用<b class='flag-5'>Linux</b><b class='flag-5'>信號(hào)量</b>實(shí)現(xiàn)互斥點(diǎn)燈