【Linux】进程通信---信号量

基本概念
  • 为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任意时刻只能有一个进程访问代码的临界区域。而信号量就可以提供这样的一种访问机制,让一个临界区同时只有一个进程在访问它,也就是说信号量是用来协调进程对共享资源的访问的。
  • 信号量的本质是计数器,信号量里面记录了临界资源的数目,有多少数目,信号量的值就为多少。信号量是一个特殊的变量,进程对其访问都是原子操作,且只允许对它进行等待(P操作)和发送(V操作)。最简单的信号量是只能取0和1的变量,这也是信号量最常见的一种形式,叫做二进制信号量,信号量值为1的信号量称为二元信号量。而可以取多个正整数的信号量被称为通用信号量。这里主要讨论二进制信号量
信号量和P,V 原语

信号量:

  • 互斥:P,V在同一进程中
  • 同步:P,V在不同进程中
信号量值的含义
  • S>0:S表示可用资源额个数
  • S=0:表示无可用资源,无等待进程
  • S<0:|S| 表示等待队列中进程个数
信号量结构伪代码
信号量的本质是一个计数器
struct semaphore
{
	int value:
	pointer_PCB queue;
}

P原语

P(s)
{
	s.value=s.value--;
	if(s.value < 0)
	{
		该进程状态设置为等待状态
		将该进程的PCB插入相应的等待队列s.queue末尾
	}
}

V原语

V(s)
{
	s.value=s.value++;
	if(s.value <= 0)
	{
		唤醒相应等待队列s.queue中等待的一个进程
		改变其状态为就绪态
		并将其插入就绪队列
	}
}
信号量有关函数
创建或打开信号量
  • int semget(key_t key, int nsems, int semflg)//第二个参数为信号量集中信号量的个数,第三个参数创建IPC_CREAT|0644  打开:0
  • 返回值:若成功,返回信号量集的描述符,失败-1
设置初值/销毁信号量
  • 首先创建一个联合体
union semun{  int val;}  
union senun su;     
su.val=1; 

  • int semctl( int id, int semnum, int cmd ,su(联合体对象))第一个参数为信号量集描述符,第二个参数为信号量集中第n个信号量、第三个参数设为SETVAL;最后一个参数为联合体
  • 销毁一个信号量semctl(semid, semnum, IPC_RMID)
查看信号量里的值
  • int semctl (int id, int semnum , int cmd)//cmd设置为GETVAL
  • 返回值:信号量的值
信号量PV操作
  • int  semop(int semid ,  struct sembuf *sb , int len)//第二个参数为一个结构体数组,系统会自己定义,第三个参数表示信号量集里元素的个
struct sembuf {
	int sem_num; // 第一个信号量
	int sem_op;  //  P -1, V +1
	int sem_flag; // 0
};
命令查看删除信号量集

  • 查看  ipcs   -s
  • 删除  ipcrm  -S   semid

信号量代码如下



运行结果如下

信号量的工作原理

信号量也属于进程间通信的方式之一,它的作用主要是保护临界资源因多个进程访问而造成的一系列问题,在上面的代码中,用fork创建出子进程,两个进程同时向显示屏打印字符,而在这里,两个进程的公共资源就是显示屏,因为cpu在对两个进程的调度是随机的,如果不对公共资源进行保护,打印出的结果就是A,B穿插,不是成对出现


如果让信号量可以保护临界资源,使其在任何一个时间内,都有且仅有一个进程访问,首先,fork用某种办法,得到一个相同的键值,再用相同的键值访问或者创建一个相同的信号量集,这样两个进程就可以共享信号量,我们在代码中将信号量的值设为1.以子进程为例,想要访问临界资源,首先要进行P操作申请资源,如果这时信号量的值小于0,那么它就必须挂起等待,如果这时信号量值就为1,它就指向P操作申请资源,信号量的值-1变为0,如果父进程想要申请资源,信号量值-1变为-1,其值小于0,那么挂起等待,在子进程完成对临界资源访问后,进行V操作,信号量值+1变为0,如果信号量值小于等于0,那么就唤醒父进程

SEM_UNDO

  • 当操作信号量时,sem_flg可以设为SEM_UNDO标识;SEM_UNDO用于将修改的信号量值在进程正常退出(调用exit退出或main执行完)或异常退出(如段异常,除0异常,收到KILL异常信号等)时归还给信号量
  • 如信号量的初始值为20,进程以SEM_UNDO方式操作信号量-2,-5,+1;在进程未退出时,信号量变成20-2-5+1=14;在进程退出时,将修改的值归还给信号量,信号量值变为14+2+5-1=20.


猜你喜欢

转载自blog.csdn.net/lw__sunshine/article/details/80994559
今日推荐