UNIX环境高级编程——system V信号量
1. 信号量(semaphore)主要用于保护临界资源。
进程可以根据它判断是否能访问某些共享资源。
信号量除了用于访问控制外,还可用于进程同步,也就是进程间通信。
2. 信号量分类:
a. 二值信号量: 信号量的值只能取0或1,类似于互斥锁mutex,但两者又不同:
mutex 与 二值信号量的区别:
信号量强调共享资源,只要共享资源可用,其他进程同样可以修改信号量的值;
互斥锁更强调进程,占用资源的进程使用完资源后,必须由进程本身来接锁。
b. 计数信号量:信号量的值可以取任意非负值。
system V信号量通过定义如下概念给信号量增加了另外一级复杂度。
计数信号量集:一个或多个信号量(构成一个集合),其中每个都是计数信号量。每个集合的信号量数存在一个限制,一般在25个数量级。
3.semget函数(信号量的创建)
semget函数创建一个信号量集或访问一个已存在的信号量集。
#include <sys/sem.h>
int senget(key_t key,int nsems,int oflag);
nsems参数指定集合中的信号量数。如果我们不创建一个新的信号量集,而只是访问一个已存在的集合,那就可以把该参数指定为0。一旦创建完一个信号量集,我们就不能改变其中的信号量数。
oflag值是SEM_R和SEM_A常值得组合。他们还可以与IPC _CREAT或IPC_CREAT | IPC_EXCL按位或。
当实际操作为创建一个新的信号量集时,相应的semid_ds结构的以下成员将被初始化。
(1)sem_perm结构的uid和cuid成员被置为调用进程的有效用户ID,gid和cgid成员被置为调用进程的有效组ID。
(2)oflag参数中的读写权限位存入sem_perm.mode。
(3)sem_otime被置为0,sem_ctime则被置为当前时间。
(4)sem_nsems被置为nsems参数的值。
(5)与该集合中每个信号量关联的各个sem结构并不初始化。这些结构时在以SET_VAL或SETALL命令调用semctl时初始化的。
4.semop函数(操作信号量)
使用semget打开一个信号量集后,对其中一个或多个信号量的操作就使用semop函数来执行。
#include <sys/sem.h>
int semop(int semid,struct sembuf *opsptr,size_t nops);
其中opsptr指向一个如下结构的数组:
struct sembuf{
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
};
假定有一个信号量变量sv,
P(sv):用于等待,如果sv大于0,就给它减去1,如果它的值等于0,就挂起该进程的执行
V(sv):用于发送信号,如果有其他进程因等待sv而挂起,就让它恢复运行,如果没有进程因等待sv而被挂起,就给它加1
semaphore sv=1;
loop forever{
P(sv);
critical code section;
V(sv);
noncritical code section;
}
信号量函数定义如下所示:
#include<sys/sem.h>
int semctl(int sem_id, int sem_num, int command, ...);//用来直接控制信号量信息
int semget(key_t key, int num_sems, int sem_flags);//创建一个新信号量或取得一个已有信号量的键
int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);//用于改变信号量的值
/* After the #includes, the function prototypes and the global variable, we come to the
main function. There the semaphore is created with a call to semget, which returns the
semaphore ID. If the program is the first to be called (i.e. it's called with a parameter
and argc > 1), a call is made to set_semvalue to initialize the semaphore and op_char is
set to X. */ #include <unistd.h>
#include <stdlib.h>
#include <stdio.h> #include <sys/sem.h> #include "semun.h" static int set_semvalue(void);
static void del_semvalue(void);
static int semaphore_p(void);
static int semaphore_v(void); static int sem_id; int main(int argc, char *argv[])
{
int i;
int pause_time;
char op_char = 'O'; srand((unsigned int)getpid()); sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT); if (argc > 1) {
if (!set_semvalue()) {
fprintf(stderr, "Failed to initialize semaphore\n");
exit(EXIT_FAILURE);
}
op_char = 'X';
sleep(2);
} /* Then we have a loop which enters and leaves the critical section ten times.
There, we first make a call to semaphore_p which sets the semaphore to wait, as
this program is about to enter the critical section. */ for(i = 0; i < 10; i++) { if (!semaphore_p()) exit(EXIT_FAILURE);
printf("%c", op_char);fflush(stdout);
pause_time = rand() % 3;
sleep(pause_time);
printf("%c", op_char);fflush(stdout); /* After the critical section, we call semaphore_v, setting the semaphore available,
before going through the for loop again after a random wait. After the loop, the call
to del_semvalue is made to clean up the code. */ if (!semaphore_v()) exit(EXIT_FAILURE); pause_time = rand() % 2;
sleep(pause_time);
} printf("\n%d - finished\n", getpid()); if (argc > 1) {
sleep(10);
del_semvalue();
} exit(EXIT_SUCCESS);
} /* The function set_semvalue initializes the semaphore using the SETVAL command in a
semctl call. We need to do this before we can use the semaphore. */ static int set_semvalue(void)
{
union semun sem_union; sem_union.val = 1;
if (semctl(sem_id, 0, SETVAL, sem_union) == -1) return(0);
return(1);
} /* The del_semvalue function has almost the same form, except the call to semctl uses
the command IPC_RMID to remove the semaphore's ID. */ static void del_semvalue(void)
{
union semun sem_union; if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
fprintf(stderr, "Failed to delete semaphore\n");
} /* semaphore_p changes the semaphore by -1 (waiting). */ static int semaphore_p(void)
{
struct sembuf sem_b; sem_b.sem_num = 0;
sem_b.sem_op = -1; /* P() */
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1) {
fprintf(stderr, "semaphore_p failed\n");
return(0);
}
return(1);
} /* semaphore_v is similar except for setting the sem_op part of the sembuf structure to 1,
so that the semaphore becomes available. */ static int semaphore_v(void)
{
struct sembuf sem_b; sem_b.sem_num = 0;
sem_b.sem_op = 1; /* V() */
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) == -1) {
fprintf(stderr, "semaphore_v failed\n");
return(0);
}
return(1);
}
UNIX环境高级编程——system V信号量的更多相关文章
- UNIX环境高级编程——system V消息队列
unix早期通信机制中的信号能够传送的信息量有限,管道则只能传送无格式字节流,这远远是不够的. 消息队列(也叫报文队列)客服了这些缺点: 消息队列就是一个消息的链表. 可以把消 ...
- UNIX环境高级编程——System V 共享内存区
共享内存区域是被多个进程共享的一部分物理内存.如果多个进程都把该内存区域映射到自己的虚拟地址空间,则这些进程就都可以直接访问该共享内存区域,从而可以通过该区域进行通信.共享内存是进程间共享数据的一种最 ...
- UNIX环境高级编程——system函数
system函数 功能:调用fork产生子进程,由子进程来调用:/bin/sh -c command来执行参数command所代表的命令,阻塞当前进程直到command命 令执行完毕. int sys ...
- (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (十二) 一起学 Unix 环境高级编程 (APUE) 之 进程间通信(IPC)
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- 《UNIX环境高级编程(第3版)》
<UNIX环境高级编程(第3版)> 基本信息 原书名:Advanced Programming in the UNIX Environment (3rd Edition) (Addison ...
- (十一) 一起学 Unix 环境高级编程 (APUE) 之 高级 IO
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (六) 一起学 Unix 环境高级编程 (APUE) 之 进程控制
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
随机推荐
- 【SpringMVC】<context:include-filter>和<context:exclude-filter>使用时要注意的地方
http://jinnianshilongnian.iteye.com/blog/1762632 http://blog.51cto.com/wenshengzhu/1700340 http://ww ...
- 用background-image做成条纹背景
效果: 实现: //html <div class="container"> <span class="tip span-1">1111 ...
- jupyter notebook 更换主题的方法
参考 https://github.com/dunovank/jupyter-themes install with pip # install jupyterthemes pip install j ...
- Python中迭代输出(index,value)的几种方法
需求如下:迭代输出序列的索引(index)和索引值(value). 1.创建测试列表: >>> lst = [1,2,3,4,5] 2.实现方法如下: #方法1:range()+le ...
- FJUT寒假作业第三周数蚂蚁(记录第一道并查集)
http://210.34.193.66:8080/vj/Contest.jsp?cid=162#P7 思路:用并查集合并集合,最后遍历,找到集合的根的个数. 并查集是森林,森林中的每一颗树是一个集合 ...
- PHP echo和print 语句
PHP echo 和 print 语句 在 PHP 中有两个基本的输出方式: echo 和 print. 本章节中我们会详细讨论两个语句的用法,并在实例中演示如何使用 echo 和 print. P ...
- 使用eclipse开发工具与hibernate开发者为开源一起做贡献
本文作者:苏生米沿 本文地址:http://blog.csdn.net/sushengmiyan/article/details/50525363 hibernate使用的是gradle自动构建工具, ...
- Weblogic 12c 负载均衡和session复制
在上一篇,我们介绍了weblogic集群的部署和session的复制,如何将请求负载均衡到这个三个服务器上呢? 这里提供两种方式:(1)weblogic自带的proxy代理 (2) ng ...
- ROS机器人程序设计(原书第2版)补充资料 (陆) 第六章 点云 PCL
ROS机器人程序设计(原书第2版)补充资料 (陆) 第六章 点云 PCL 书中,大部分出现hydro的地方,直接替换为indigo或jade或kinetic,即可在对应版本中使用. RGBD深度摄像头 ...
- tolua++没法用
tolua++没法用(金庆的专栏)觉得从C++头文件生成lua绑定代码的方法比较简单,想试试tolua++.从Github获取toluapp:https://github.com/LuaDist/to ...