进程间通信---信号量

16 篇文章 0 订阅

信号量是一个计数器,用于多进程或者多线程之间的数据同步,最常用的是二进制信号量。

为了获取资源,进程需要进行如下操作:

1 测试控制该资源的信号量

2 若信号量的值为正,表明进程可以使用此资源。进程将信号量的值减1

3 若信号量的值为0,则进程进入休眠状态,直至信号量大于零,进程被唤醒。

 

在linux中,信号量的测试和-1操作是原子性的,在内核中实现。

下面就来介绍XSI信号量的操作,主要用到了三个函数

1 int  semget(key_t key,int nsems,int flag);

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

3 int semop(int semid,struct sembuf semoparray[], int nops);

下面来逐一介绍:

int  semget(key_t key,int nsems,int flag) 的功能是创建一个信号量的集合。

参数key是信号量的标识,当在一个进程中创建了信号量之后,可以使用这个key在别的进程中打开。

参数 nsems表示信号量集合中包含的信号量的个数。

参数 flags为创建信号量的标志,有IPC_CREAT等,创建的时候,需要制定IPC_CREAT标志。

此函式也可以用来打开一个已经存在的信号量,此时key为此信号量创建时的key,nsems和flag填0即可。

 

int  semctl(int semid,int semnum,int cmd,union semun arg),这个函数用来对信号量进行控制。

参数semid唯一标识系统中已经创建的信号量

参数semnum表示要操作的信号量集合中信号量的序号,序号从0开始,到semnum - 1.

参数cmd表示需要进行的操作命令,共有十个命令,常用的有SETVAL,GETVAL

参数arg的作用视cmd而定,相信的命令情况参考man手册。

 

int semop(int semid,struct sembuf semoparray[], int nops) 可以获取或者释放一个信号量

参数semid是信号量的标识id,主要的参数是semoparray,其类型是:

struct sembuf

{

    unsigned short sem_num;   //要操作的信号量在信号量集合中的序号

    short                sem_op;      //1表示释放信号量,-1表示获取资源

    short                sem_flg;      //IPC_NOWAIT,SEM_UNDO,若设为IPC_NOWAIT当不能获取资源时不阻塞,返回EAGAIN

};

参数nops表示struct sembuf数组中元素的个数

 

光说不练,印象不够深刻,实践是学习编程的最好的方法,下面就通过一个小程序来演示一下信号量的使用,程序分为两部分,一个服务端,一个客户端,服务端创建一个信号量,获取信号量资源,休眠20秒钟后释放信号量。客户端启动时去获取服务端创建的信号量,直到服务端释放后才能获取。

---------------------------------------------------------------------------------------------------------------

semsvr.cpp

-----------------------------------------------------------------------------------------------------------------

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

#include <unistd.h>
#include <iostream>

using namespace std;

union semun {
 int val;
 struct semid_ds *buf;
 unsigned short *array;
} arg;

 

//创建一个信号量集合

int Create_Sem(int key)
{
 int semid = 0;
 if((semid = semget(key,1,IPC_CREAT)) == -1)
 {
  cout << "create sem failed" << endl;
  return -1;
 }
 cout << "create sem success" << endl;
 union semun sem;
 sem.val = 1;
 semctl(semid,0,SETVAL,sem);  //初始化信号量的值为1,表明只允许一个进程拥有这个信号量
 cout << "create compelte" << endl;
 return semid;
}

 

//打开已经存在的信号量

int Open_Sem(int key)
{
 return semget(key,0,0);
}

 

//获取信号量资源

int Lock_Sem(int semid)
{
 struct sembuf buff;
 buff.sem_num = 0;
 buff.sem_op = -1;
 return semop(semid,&buff,1);
}

 

//释放信号量资源

int Release_Sem(int semid)
{
 struct sembuf buff;
 buff.sem_num = 0;
 buff.sem_op = 1;
 return semop(semid,&buff,1);
}

 

//删除信号量

int Delete_Sem(int semid)
{
 return semctl(semid,0,IPC_RMID,0);
}
int main()
{
 int semid = Create_Sem(12345);
 if(semid == -1)
 {
  cout << "create sem failed" << endl;
  return 0;
 }
 if(Lock_Sem(semid) == -1)
 {
  cout << "lock sem failed" << endl;
  return 0;
 }
 cout << "lock sem success" << endl;
 sleep(20);
 Release_Sem(semid);
 cout << "release sem success" << endl;
 return 0;
}
----------------------------------------------------------------------------------------------------------------

semcli.cpp

-----------------------------------------------------------------------------------------------------------------

 

int main()
{
 int semid = Open_Sem(12345);
 if(semid == -1)
 {
  cout << "open sem failed" << endl;
  return 0;
 }
 if(Lock_Sem(semid) == -1)
 {
  cout << "lock sem failed" << endl;
  return 0;
 }
 cout << "lock success" << endl;
 Delete_Sem(semid);
 return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值