linux进程间通信--信号量

Posted sucfrperperseverance

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux进程间通信--信号量相关的知识,希望对你有一定的参考价值。

信号灯(信号量)集

在多任务操作系统环境下,多个进程或线程会同时运行,多个任务可能可能为了完成同一个目标会相互协作,这样形成任务之间的同步关系;同样,在不同任务之间为了争夺有限的系统资源(硬件或软件资源)会进入竞争状态,这就是任务之间的互斥关系

任务之间的同步与互斥关系存在的根源在于临界资源。临界资源是指同一个时刻只允许有限个(通常只有一个)任务可以访问(读)或修改(写)的资源,通常包括硬件资源和软件资源,访问临界资源的代码称为临界区

POSIX 线程中的同步用的是无名信号量
进程间的同步使用的是IPC 对象[信号灯集]

信号灯集:信号灯集合,每一个信号灯都可以用来表示一类资源,其值表示资源的个数

其中信号量(信号灯集)对应于某一种资源,取一个非负整数值,信号量值指的是当前可用的资源数量,若它为0这意味着目前没有可用的资源

 

1.获得key值

第一种:
  key_t ftok(const char *pathname, int proj_id);
参数:
@pathname 已经存在的文件路径
@proj_id 获取这个整数的低8bit
返回值:
  成功返回 key值,失败返回-1


第二种:
将key值指定为IPC_PRIVATE ,当IPC对象在亲缘关系进程间通信的时候

(1)创建信号灯集
int semget(key_t key, int nsems, int semflg);
参数:
@key IPC_PRIVATE , ftok()
@nsems 信号灯集中信号灯的个数 
@semflg IPC_CREAT | 0666,IPC_CREAT | IPC_EXCL
返回值:
成功返回ID,失败返回-1

 

(2)初始化信号灯集中信号灯的值

int semctl(int semid, int semnum, int cmd, union semun arg);
参数:
@semid 信号灯集的ID
@semnum 信号灯的编号[编号从0开始]
@cmd SETVAL[设置信号灯的值] ,GETVAL(获取信号灯的值),IPC_RMID[删除信号灯集]
返回值:
成功返回0,失败返回-1

思考:将信号灯集中的1号信号灯初始化为1?

其中arg:是union semnum 结构,可能在某些系统中不给出改结构的定义,这时必须由程序员自己定义

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) */
};

//初始化指定编号的sem_num信号灯集为value

void init_sem_value(int sem_id,int sem_num,int value)
{
  union semun sem_val;

  sem_val.val = value;

if(semctl(sem_id,sem_num,SETVAL,sem_val) < 0)
{
...
}

return ;
}

PV原子操作的具体定义:

P操作:如果有可用资源(信号量值大于0),则占用一个资源(信号量值减一,进入临界区代码);如果没有可用资源(信号值等于0),则被阻塞,直到系统将资源分配给该任务(进入等待队列,一直等到有资源时被唤醒)

V操作:如果该信号量在等待队列中有任务在等待资源,则唤醒一个阻塞任务,如果没有任务等待他,则释放一个资源(信号量值加1)

(3)PV操作
int semop(int semid, struct sembuf *sops, unsigned nsops);
功能: 完成PV操作
参数:
 @semid 信号灯集的ID
 @sops 操作方式结构体首地址
 @nsops 操作信号灯的个数
返回值:
成功返回0,失败返回-1

struct sembuf
{
unsigned short sem_num; /* semaphore number  ,信号量的编号,使用单个信号量时,通常取值为0*/
short sem_op; /* semaphore operation  信号量操作,取-1表示P操作,取+1表示V操作*/
short sem_flg; /* operation flags 通常设置为SEM_UNDO,这样在进程没有释放信号量退出时,系统会自动释放该进程中未释放的信号量 */
};

sem_op :
<1>0 等待信号灯的值变成0
<2>1 释放资源,V操作
<3>-1 申请资源,P操作

sem_flg:
0 : 阻塞方式
IPC_NOWAIT : 非阻塞方式调用
SEM_UNDO : 进程结束的时候,它申请的资源自动释放

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

P/V操作封装如下:
void P(int sem_id,int sem_num)
{
  struct sembuf sem;

  sem.sem_num = sem_num;
  sem.sem_op = -1;
  sem.sem_flg = 0;

  if(semop(sem_id,&sem,1) < 0)
  {
    ....
  }
}

void V(int sem_id,int sem_num)
{
  struct sembuf sem;

  sem.sem_num = sem_num;
  sem.sem_op = 1;
  sem.sem_flg = 0;

  if(semop(sem_id,&sem,1) < 0)
  {
  ....
  }
}

 














































































以上是关于linux进程间通信--信号量的主要内容,如果未能解决你的问题,请参考以下文章

Linux-进程间通信

linux进程间通信--信号通信

Linux的进程/线程间通信

Linux的进程/线程间通信

Linux进程间通信 共享内存+信号量+简单样例

深刻理解Linux进程间通信(IPC)