您的位置:首页 > 运维架构 > Linux

信号量(sem)

2016-04-19 17:26 801 查看
一、信号量:(数据操作锁)控制进程间互斥、同步等,协调多个程序同时访问一个共享资源。
工作原理:信号量只能有两种操作等待和操作,即:P V操作,必须是原子操作。

P(sv):如果 sv 的值大于零就减一;如果它的值为零,就挂起;

V(sv):如果有被挂起的,恢复运行,如果没有就加一。

二、函数原型:
int semget(key_t key, int nsems,int semflg);

int semop(int semid,struct sembuf *sops,size_t nsops);

int semctl(int semid, int semnum, int cmd, ...);
/*
* semid:信号量集的标识符; semnum:第几个信号量;
* cmd:需要执行的命令,根据命令的不同,函数有三个或四个参数(union)

*/

cmd:IPC_RMID,立即删除信号集,唤醒被阻塞的进程;
cmd:SETVAL,设置信号量集中的一个单独的信号量的值。

cmd:GETALL用于读取信号量集中的所有信号量的值。
union semun
{
int val;

struct semid_ds *buf;

unsigned short *array;

struct seminfo *_buf;

};//用户需自己定义声明

struct sembuf
{
unsigned short sem_num;

short sem_op;

short sem_flg;

};

三、代码实现:
//sem.h
#pragma once

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

#define _PATH_ "."
#define _ID_ 0x666

static int op_sem(int sem_id, int op, int which);
int creat_sem(int _sem_num);
int get_sem();
int init_sem(int _sem_id, int _which);
int sem_p(int _sem_id, int _which);
int sem_v(int _sem_id, int _which);
int destroy_sem(int _sem_id);

union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
//sem.c
#include"sem.h"

int creat_sem(int snum)
{
int flags = IPC_CREAT|IPC_EXCL|0666;
key_t key = ftok(_PATH_, _ID_);
if(key < 0)
{
perror("ftok");
return -1;
}
return semget(key, snum, flags);
}

int get_sem()
{
key_t key = ftok(_PATH_, _ID_);
if(key < 0)
{
perror("ftok");
return -1;
}
return semget(key, 0, IPC_CREAT);
}

static int op_sem(int sem_id, int op, int which)
{
struct sembuf sem;
memset(&sem, '\0',sizeof(sem));
sem.sem_num = which;
sem.sem_op = op;
sem.sem_flg = 0;
if(semop(sem_id, &sem, 1) < 0)
{
perror("semop");
return -1;
}
return 0;
}

int sem_p(int sem_id, int which)
{
return op_sem(sem_id, -1, which);
}

int sem_v(int sem_id, int which)
{
return op_sem(sem_id, 1, which);
}

int init_sem(int sem_id, int which)
{
union semun _semun;
_semun.val = 1;
if(semctl(sem_id, SETVAL, which, _semun) < 0)
{
perror("semctl");
return -1;
}
return 0;
}

int destroy_sem(int sem_id)
{
if(semctl(sem_id, 0, IPC_RMID, NULL) < 0)
{
perror("semctl");
return -1;
}
return 0;
}
//test.c
#include"sem.h"

int main()
{
int sem_id = creat_sem(1);
if(sem_id < 0)
{
printf("creat_sem error");
return -1;
}
init_sem(sem_id, 0);
pid_t id  = fork();
if(id < 0)
{
perror("fork");
return -1;
}
else if(id == 0)
{
int sem_id = get_sem(1);
while(1)
{
sem_p(sem_id, 0);
printf("A");
sleep(1);
fflush(stdout);
printf("A");
sleep(2);
fflush(stdout);
sem_v(sem_id, 0);
}
}
else
{
while(1)
{
sem_p(sem_id, 0);
printf("B");
fflush(stdout);
printf("B");
sleep(1);
fflush(stdout);
sem_v(sem_id, 0);
}
waitpid(id, NULL, 0);
destroy_sem(sem_id);
}
return 0;
}
四、实现结果:

使用信号量之前



使用信号量之后


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Linux sem 信号量