SYSTEM-V IPC信号量 详解

SYSTEM-V IPC信号量 详解

(1)概述
 1.消息队列的作用是进程之间传递消息。 
 2.信号量的作用是为了同步多个进程的操作
 3.内核会负责维护信号量的值,并确保其值不小于 0 。
 4.信号量上支持的操作
 · 将信号量的值设置成一个绝对值。
 · 在信号量当前值的基础上加上一个数量。
 · 在信号量当前值的基础上减去一个数量。
 · 等待信号量的值等于 0 。
 5.二值信号量
  1.它只有两种合法值: 0 和 1 ,对应一个可用的资源。
  2.若当前有资源可用,则与之对应的二值信号量的值为 1 ;
  3.若资源已被占用,则与之对应的二值信号量的值为 0 。
  4.当进程申请资源时,如果当前信号量的那么进程会陷入阻塞,直到有其他进程释放资源,将信号量的值加 1 才能被唤醒。
 6.互斥量( mutex )是用来保护临界区的,所谓临界区,是指同一时间只能容许一个进程进入。而信号量( semaphore )是用来管理资源的,资源的个数不一定是 1 ,可能同时存在多个一模一样的资源,因此容许多个进程同时使用资源。
 7.信号量是互斥量的一个扩展,由于资源数目增多,增强了并行度。但是这仅仅是一个方面。更重要的区别是,互斥量和信号量解决的问题是不同的。
 8.互斥量的关键在于互斥、排它,同一时间只允许一个线程访问临界区。决定了解铃还须系铃人,即加锁进程必然也是解锁进程,
 9.而信号量的关键在于资源的多少和有无。申请资源的进程不一定要释放资源,信号量同样可以用于生产者 - 消费者的场景。在这种场景下,
 生产者进程只负责增加信号量的值,而消费者进程只负责减少信号量的值。彼此之间通过信号量的值来同步。
 10.和二值信号量相比, System V 信号量在两个维度上都做了扩展。
  第一,资源的数目可以是多个。资源个数超过 1 个的信号量称为计数信号量
  第二,允许同时管理多种资源,由多个计数信号量组成的一个集合称为计数信号量集,每个计数信号量管理一种资源。
 11. fork前创建的信号量,父子进程的信号量是实时自动同步的

(2)创建或打开信号量

int semget(key_t key, int nsems, int semflg);
	第二个参数 nsems 表示信号量集中信号量的个数。换句话说,就是要控制几种资源。大部分情况下只控制一种。
	semflg 支持多种标志位。目前支持 IPC_CREAT 和 IPC_EXCL 标志位,其含义不再赘述。

(3)操作信号量
int semop(int semid, struct sembuf *sops, unsigned nsops);
 第二个参数是 sembuf 类型的指针, sem_num 解决的是操作哪个信号量的问题
 第三个参数是表示要同时操作几个信号量
   通常的方法:
  1.抢占资源型
   同一个资源互斥访问:
    [资源]
    setctl 1     // 初始化为1
   p1     p2
semop-1    semop-1 // 使用资源前,必须先占有资源
  使用临界资源资源
sleep(1)    sleep(1) // 将当前进程挂起1秒, 给其他进程抢占资源的机会
sem+1    sem+1   // 释放资源

  

2.生产者消费者类型  //(共享内存和信号量的搭配使用就是)
      [资源]
      setctl0    // 初始化为0
   生产者  消费者
   semop+1 semop-1 // 二者完全独立, 当资源消耗完后, 消费者陷入阻塞

(4)控制信号量

int semctl(int semid, int semnum, int cmd,/* union semun arg*/);

(5)通常的封装

  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 sema_getval(int semid, int index)
	{	union semun ignore_arg;
		return semctl(semid, index, GETVAL, ignore_arg);
	}
	// 设置信号量集中指定信号量为value
	int sema_setval(int semid, int index, int val)
	{	union semun arg;
		arg.val = val;
		return semctl(semid, index, SETVAL, arg);
	}
	// 立即删除信号量集
	int sema_rmid(int semid)
	{	union semun ignore_arg;
		int ignore_index;
		return semctl(semid, ignore_index, IPC_RMID, ignore_arg);
	}
	/* 操作信号量 */ 
	// 申请资源(操作一个信号量)
	int semaphore_wait (int semid, int index)
	{
		struct sembuf operations[1];
		operations[0].sem_num = index;			// 操作一组信号量中的哪一个信号量
		operations[0].sem_op = -1;				// 信号量0的值 -1
		operations[0].sem_flg |= SEM_UNDO;    // 进程退出后恢复信号量(成对出现)
		return semop(semid, operations, 1);		// 信号量集合操作
	}
	// 释放资源(操作一个信号量)
	int semaphore_post(int semid, int index)
	{
		struct sembuf operations[1];
		operations[0].sem_num = index;			// 操作一组信号量中的哪一个信号量
		operations[0].sem_op = 1;				// 信号量0的值 + 1
		operations[0].sem_flg |= SEM_UNDO;    // 进程退出后恢复信号量(成对出现)
		return semop(semid, operations, 1);
	}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值