0
点赞
收藏
分享

微信扫一扫

【Linux】IPC通信——信号量的使用

凌得涂 2022-04-14 阅读 75

👉一、前言


 

👉二、认识信号量

1、信号量的概念

  • 信号量是一种变量,它只能取正整数值,对这些正整数只能进行两种操作:等待信号
  • 最简单的信号量是一个只能取“0”和“1”值的变量,也就是人们常说的“二进制信号量
  • 假设进程一和进程二共享同一个信号量,有如下两个场景

场景一

        初始sv=1,进程一先访问信号量,进行P操作后sv=0,此时进程二也访问了信号量并想要执行P操作,但是由于此时sv=0,所以进程二只能先挂起,直至进程一执行完业务,进行V操作后,即sv+1=1后,进程二恢复执行

 

场景二

        进程一业务做完,执行V操作,sv+1=1,进程二恢复执行P操作,sv-1=0。


2、信号量的作用

  • 信号量可以解决进程同步问题

 

下面我们来学习一下信号量的相关函数


 

👉三、信号量相关函数

1、semget()函数

  • 函数功能:创建一个新的信号量或者取得一个现有信号量的键字
  • 代码示例
int sem_create(key_t key, int nsems)
{
	int res = semget(key, nsems, IPC_CREAT | 0777);
	if (res < 0)
	{
		perror("semget error");
	}
	return res;
}

2、semctl()函数

  • 函数功能:允许我们直接控制信号量的信息
  • 补充
  • union semun复合结构如下
  • 代码示例
union semun 
{
	int              val;    /* Value for SETVAL */ //设置具体值
	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 sem_setval(int semid, int senindex, int val)
{
	//senindex:信号量的编号,​​​​​​​一般取值为 0

	union semun arg;
	arg.val = val;//设置具体值

	int res = semctl(semid, senindex, SETVAL, arg);
	if (res < 0)
	{
		perror("semctl error");
	}

	return res;
}

3、semop()函数

  • 函数功能:改变信号量的键值
  • struct sembuf 结构体如下
  • 代码示例
//信号量p操作 -1
int sem_p(int semid, int semindex)
{
	//senindex:信号量的编号,​​​​​​​一般取值为 0

	struct sembuf buf = { semindex, -1, SEM_UNDO };
	int res = semop(semid, &buf, 1);
	if (res < 0)
	{
		perror("semop error");
	}
	return res;
}

//信号量v操作 +1
int sem_v(int semid, int semindex)
{
	struct sembuf buf = { semindex, 1, SEM_UNDO };
	int res = semop(semid, &buf, 1);
	if (res < 0)
	{
		perror("semop error");
	}
	return res;
}

👉四、主函数测试

  • 创建两个工程,访问同一个信号量,并执行P、V操作。
  • 调用的函数为上面示例代码所封装的

1、工程一

  • 工程一为创建信号量,并赋初值为1
int main()
{
	//如果1001信号量存在则访问 不存在则创建
	int semid = sem_create((key_t)1001, 1);
	//将信号量数组下标为0的数据设置为1
	sem_setval(semid, 0, 1);

	//加锁 信号量数组下标为0 执行P操作后信号量的值为0
	sem_p(semid, 0);

	for (int i = 0; i < 5; i++)
	{
		cout << "第一个进程正在运行…… i = " << i << endl;
		sleep(1);
	}

	//解锁,执行V操作后 信号量的值为1
	sem_v(semid, 0);

	return 0;
}

2、工程二

  • 工程二为访问上一个工程创建的信号量,不需要再赋初值。
int main()
{
	//如果1001信号量存在则访问 不存在则创建
	int semid = sem_create((key_t)1001, 1);
	//加锁 -1
	sem_p(semid, 0);//阻塞无法继续执行  只有上一个工程结束后才执行

	for (int i = 0; i < 5; i++)
	{
		cout << "第二个进程正在运行…… i = " << i << endl;
		sleep(1);
	}

	//解锁 +1
	sem_v(semid, 0);
	return 0;
}

3、先执行工程一立马执行工程二

  • 测试效果如下

 

🔔Tip

 

😘The end ……🔚

举报

相关推荐

0 条评论