信号量(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
使用信号量之前
使用信号量之后
工作原理:信号量只能有两种操作等待和操作,即: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 socket 初步
- Linux Kernel 4.0 RC5 发布!
- linux lsof详解
- linux 文件权限
- Linux 执行数学运算
- 10 篇对初学者和专家都有用的 Linux 命令教程
- Linux 与 Windows 对UNICODE 的处理方式
- Ubuntu12.04下QQ完美走起啊!走起啊!有木有啊!
- 解決Linux下Android开发真机调试设备不被识别问题
- 运维入门
- 运维提升
- Linux 自检和 SystemTap
- Ubuntu Linux使用体验
- c语言实现hashmap(转载)
- Linux 信号signal处理机制
- linux下mysql添加用户
- Scientific Linux 5.5 图形安装教程
- Linux 下无损图片压缩小工具介绍