linux进程间通信—信号量

(一)概念
1.临界资源:同一时刻,只允许一个或有限个进程或者线程访问的资源。
2.临界区:访问临界资源的代码段。
3.原子操作:不可分割或者中断的操作,操作一旦开始执行,就必须执行结束,中途不能被任何原因打断。
4.信号量类似于计数器,是一个特殊的变量,值可以改变,但只能取正整数值,并且对它的加1和减1操作是原子操作。如果信号量值为0,那么再进行减1操作时就会阻塞。信号量的初始值,代表资源数量。
作用:控制多个进程对临界资源的访问,使程序在同一个时刻,只有一个进程访问临界资源(进行进程间同步控制)。原理就是控制程序的执行速度。
进程间同步控制:

  • 同步执行:两个或多个进程需要协同执行,进程A的执行需要进程B提供支持。
  • 异步执行:进程A和进程B互不干扰,在B给A发送数据前,A不会等待数据到达。

(二)信号量的操作:
所需头文件:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

1.创建:
(1)函数:

int semget(key_t key,int nsems,int semflg);//第一次是同创建信号量,之后使用就是获取信号量

(2)参数:

  • key:进程间通信键值,通过调用ftok()函数得到的键值。
  • nsems:创建的信号量的个数。如果只是访问而不创建则可以指定该参数为0,一旦创建了该信号量,就不能更改其信号量个数,只要不删除该信号量,重新调用该函数创建该键值的信号量,该函数只能返回以前创建的值,不会重新创建
  • semflg:标识函数的行为及信号量的权限,其取值如下:
  • IPC_CREAT:创建信号量
  • IPC_EXCL:检测信号量是否存在
  • 位或权限位:信号量位或权限位后可以设置信号量的访问权限,格式和open函数的mode_t一样。

(3)返回值:

  • 成功:信号量标识符
  • 失败:返回-1

2.控制信号量集合、信号量
(1)函数:

int semctl(int semid,int semnum,int cmd,...)//对信号量集合及集合中的信号量进行操作

(2)参数:

  • semid:信号量集合标识符
  • semnum:集合中信号量的序号,指定对哪个信号量进行操作,只对几个特殊的cmd操作有意义。
  • cmd:信号量控制类型。semctl()函数可能有3个参数,也可能有4个参数,参数的个数由cmd决定。当有4个参数时,第4个参数为联合体。
union semun
{
	int val;//信号量的值
	struct semid_ds* buf;//信号量集合信息
	unsigned short* array;//信号量值的数组
	struct seminfo* _buf;//信号量限制信息	
};
  • GETVAL:获取信号量的值。此时函数有3个参数,semctl()函数的返回值即为信号量的值。
  • SETVAL:设置信号量的值。此时函数有4个参数。第4个参数为联合体中的val,其值为信号量的值。
  • IPC_STAT:获取信号量集合的信息。此时函数有4个参数。第4个参数为联合体中的_buf。
  • IPC_SET:设置信号量集合的信息。此时函数有4个参数。第4个参数为联合体中的_buf。
  • IPC_RMID:删除信号量集。此时函数有3个参数,第2个参数semnum不起作用。
  • GETALL:获取所有信号量的值。此时函数有4个参数,第2个参数semnum不起作用。第4个参数为联合体中的array,其值用来存放所有信号量值的数组的首地址。
  • SETALL:设置所有信号量的值。和上面的一样。
  • IPC_INFO:获取信号量集合的限制信息。此时函数有4个参数,第2个参数semnum不起作用。第4个参数为联合体中的_buf。
  • GETPID:获取信号的进程号,即最后操作信号量的进程。此时函数有3个参数。semctl()函数的返回值即为信号的进程号。
  • GETNCNT:获取等待信号的值递增的进程数。此时函数有3个参数。semctl()函数的返回值即为进程数。
  • GETZCNT:获取等待信号的值递减的进程数。此时函数有3个参数。semctl()函数的返回值即为进程数。

(3)返回值:

  • 成功:0
  • 失败:-1

3.操作信号量:
(1)函数:

int semop(int semid,struct sembuf* sops,unsigned nsops);//操作信号量,主要进行信号量加减操作

(2)参数:

  • semis:信号量集合标识符
  • sops:操作信号量的结构体(struct sembuf)数组的首地址(结构体定义在sys/sem.h),此结构体中的数据表明了对信号量进行的操作。
struct sembuf
{
	unsigned short sem_num;//信号量的序号
	short sem_op;//信号量的操作值
	short sem_flg;//信号量的操作标识
};

sem_num:信号量集合中信号量的序号
sem_op取值如下:

  • sem_op>0:信号量的值在原来的基础上加上此值。
  • sem_op<0:如果信号量的值小于semop的绝对值,则挂起操作进程。如果信号量的值大于等于semop的绝对值,则信号量的值在原来的基础上减去semop的绝对值。
  • sem_op=0:对信号量的值进行是否为0 的测试。若为0则函数立即返回,若不为0则阻塞调用进程。

sem_flag取值如下:

  • IPC_NOWAIT:在对信号量的操作不能执行的情况下使函数立即返回。

  • SEM_UNDO:当进程推出后,该进程对信号量进行的操作将被撤销。

  • nsops:操作信号量的结构体数组元素的个数。

(3)返回值:

  • 成功:0
  • 失败:-1
    实例1:
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
  key_t key;
  key = ftok(".",2016);
  if(key == -1)
  {
    perror("ftok error");
  }
  
  system("ipcs -s");
  int semid;
  semid = semget(key,1,IPC_CREAT|0666);
  if(semid == -1)
  {
    perror("semget error");
  }

  system("ipcs -s");

  semctl(semid,0,IPC_RMID);

  system("ipcs -s");
  return 0;
}

运行结果:
在这里插入图片描述
实例2:

#include <sys/sem.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>

#define IPC_INFO 3
int main()
{
  key_t key;
  key = ftok(".",2016);
  if(key == -1)
  {
    perror("ftok error");
  }
  
  system("ipcs -s");
  int semid;
  semid = semget(key,1,IPC_CREAT|0666);
  if(semid == -1)
  {
    perror("semget error");
  }

  system("ipcs -s");

  struct seminfo buf;
  semctl(semid,0,IPC_INFO,&buf);
  
  printf("buf.semmni = %d\n",buf.semmni);
  printf("buf.semmns = %d\n",buf.semmns);
  printf("buf.semmnu = %d\n",buf.semmnu);
  printf("buf.semmsl = %d\n",buf.semmsl);
  printf("buf.semopm = %d\n",buf.semopm);
  printf("buf.semume = %d\n",buf.semume);
  printf("buf.semusz = %d\n",buf.semusz);
  printf("buf.semvmx = %d\n",buf.semvmx);
  printf("buf.semaem = %d\n",buf.semaem);

  semctl(semid,0,IPC_RMID);
  system("ipcs -s");
  return 0;
}

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值