信号量--System V信号量 与 Posix信号量

举报
看,未来 发表于 2020/12/30 00:53:17 2020/12/30
【摘要】 信号量是什么 信号量是一种计数器,用来控制对多个进程/线程共享的资源进行访问。常和锁一同使用。 在某个进程/线程正在对某个资源进行访问时,信号量可以阻止另一个进程/线程去打扰。 生产者和消费者模型是信号量的典型使用。 为什么信号量分两套(两套有什么区别) 简要的说,Posix是“可移植操作系统接口(Portable Operating System Int...

信号量是什么

信号量是一种计数器,用来控制对多个进程/线程共享的资源进行访问。常和锁一同使用。
在某个进程/线程正在对某个资源进行访问时,信号量可以阻止另一个进程/线程去打扰。
生产者和消费者模型是信号量的典型使用。

为什么信号量分两套(两套有什么区别)

简要的说,Posix是“可移植操作系统接口(Portable Operating System Interface )的首字母简写,但它并不是一个单一的标准,而是一个电气与电子工程学会即IEEE开发的一系列标准,它还是由ISO(国际标准化组织)和IEC(国际电工委员会)采纳的国际标准。而System v是Unix操作系统众多版本的一个分支,它最初是由AT&T在1983年第一次发布,System v一共有四个版本,而最成功的是System V Release 4,或者称为SVR4。这样看来,一个是Unix 的标准之一(另一个标准是Open Group),一个是Unix众多版本的分支之一(其他的分支还有Linux跟BSD),应该来说,Posix标准正变得越来越流行,很多厂家开始采用这一标准。

那么两者有什么区别,或者说,应用场景:
1、POSIX信号量常用于线程;system v信号量常用于进程的同步。

2、从使用的角度,System V 信号量的使用比较复杂,而 POSIX 信号量使用起来相对简单。

3、对 POSIX 来说,信号量是个非负整数。而 System V 信号量则是一个或多个信号量的集合,它对应的是一个信号量结构体,这个结构体是为 System V IPC 服务的,信号量只不过是它的一部分。

4、Posix信号量是基于内存的,即信号量值是放在共享内存中的,它是由可能与文件系统中的路径名对应的名字来标识的。而System v信号量则是基于内核的,它放在内核里面。

5、POSIX 信号量的头文件是 <semaphore.h>,而 System V 信号量的头文件是 <sys/sem.h>。

6、Posix还有有名信号量,一般用于进程同步, 有名信号量是内核持续的。

【本文不对有名Posix做过多介绍】

怎么实现呢?

1、新建信号量

System V Posix(无名)
int semget(key_t key,int nsems,int semflg); int sem_init(sem_t *sem,int pshared,int values);
  • system V
#include<sys/type.h>
#include<sys/ipc.h>
#include<sys/sem.h>

int semget(key_t key,int nsems,int semflg);
/*
nsems:创建多少个
semflg:IPC_CREAT、IPC_EXCL;
*/

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

利用System V函数包装建立信号量的代码;

typedef int sem_t;
union semun
{
	int val; struct semid_ds *buf;	//semid_ds的指针
	unsigned short *array;	//数组类型
} arg; //定义一个全局变量

sem_t CreateSem(key_t key,int value)
{
	union semun sem;	//信号量结构变量
	sem_t sem_id;
	sem.val = value;	//设置初始值

	sem_id = semget(key,0,IPC_CREAT|0666);	//获取信号量id
	if(sem_id == -1)
	{
		printf("create sem failed\n"); exit(-1);
	}
	semctl(sem_id,0,SETVAL,sem);			//发送命令,建立value个初始信号量
	return sem_id;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • Posix信号量:直接用那个函数就好了,可以加一个报错保险。
    【后面的栗子都一样,Posix就这么简单】

2、PV操作(增减信号量)

System V Posix(无名)
int semop(int semid,struct sembuf *sops,unsigned nsops); sem_post(sem_t *sem); sem_wait(sem_t *sem);
  • System V
/*
参数释义:
struct sembuf
{
	ushort sem_num;	//信号量的编号
	short sem_op;	//信号量的操作 {正负零}	
	short sem_flg;	//信号量的操作标志 {NOWAIT}
};
//sem_op取0表示将信号量设为睡眠状态,直到信号量的值为0为止

nsops:该数组中操作的个数
*/

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
int Sem_P(sem_t semid)
{
	struct sembuf sops = {0,+1,IPC_NOWAIT};
	return (semop(semid,&sops,1));
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
intSem_V(sem_t semid)
{
	struct sembuf sops = {0,-1,IPC_NOWAIT};
	return (semop(semid,&sops,1));
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

P操作:进行增加一个信号量的值的操作
V操作:进行减少一个信号量的值的操作

  • Posix
    P:sem_post(sem_t *sem);
    V:sem_wait(sem_t *sem);

3、控制信号量参数

System V Posix
int semctl(int semid,int semnum,int cmd,…) ; /
#include<sys/type.h>
#include<sys/ipc.h>
#include<sys/sem.h>
int semctl(int semid,int semnum,int cmd,...);

/*
该函数是在信号量的集合上执行控制操作函数。
参数释义:
semnum:将要被执行操作的信号量编号。对于集合中的第一个信号量,它的值为0。
cmd:
	IPC_STAT:获取某个集合的semid_ds结构,并把它存在semun联合体的buf中。
	IPC_SET:设置某个集合的semid_ds中的ipc_perm成员的值。该命令所取值从buf中获取。
	IPC_RMID:从内核删除该集合。
	GETTALL:用于获取集合中所有的信号量的值,存放在semun联合体的array中。
	GETPID:返回最后一次调用semop的PID。
	GETVAL:返回集合中某个信号量的值。
	GETZCNT:返回正在等待资源利用率达到百分百的进程的数目。
	SETALL:把集合中所有信号量的值设置为semun联合体中array中的值。
	SETVAL:把集合中某个信号量的值设置为semun联合体中val的值。
*/

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

//栗子就不放了

4、销毁信号量

System V Posix(无名)
ctl自定义 int sem_destory(sem_t *sem);
  • System V
void DestroySem(sem_t semid)
{
	union semun sem;
	sem.val = 0;
	se,ctl(semid,0,IPC_RMID,sem);
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

最后,放一串生产消费者的代码


//实现线程互斥

#include <iostream>
#include<unistd.h>
#include<stdlib.h>
#include<semaphore.h>
#include<errno.h>
#include<pthread.h>
using namespace std;
 
sem_t sem;
void* productor(void* arg)
{ while(1) { sem_wait(&sem); cout << "create noodle!!!" << endl; sem_post(&sem); usleep(10); } return NULL;
}
 
void* consumer(void* arg)
{ while(1) { sem_wait(&sem); cout << "eat noodle!!!" << endl; sem_post(&sem); usleep(10); } return NULL;
}
int main()
{ pthread_t tid1,tid2; sem_init(&sem, 0, 1); pthread_create(&tid1, NULL, productor, NULL); pthread_create(&tid2, NULL, consumer, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); sem_destroy(&sem); return 0;
} 
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

文章来源: lion-wu.blog.csdn.net,作者:看,未来,版权归原作者所有,如需转载,请联系作者。

原文链接:lion-wu.blog.csdn.net/article/details/105013213

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。