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信号量的更多相关文章

  1. UNIX环境高级编程——system V消息队列

    unix早期通信机制中的信号能够传送的信息量有限,管道则只能传送无格式字节流,这远远是不够的.     消息队列(也叫报文队列)客服了这些缺点:     消息队列就是一个消息的链表.     可以把消 ...

  2. UNIX环境高级编程——System V 共享内存区

    共享内存区域是被多个进程共享的一部分物理内存.如果多个进程都把该内存区域映射到自己的虚拟地址空间,则这些进程就都可以直接访问该共享内存区域,从而可以通过该区域进行通信.共享内存是进程间共享数据的一种最 ...

  3. UNIX环境高级编程——system函数

    system函数 功能:调用fork产生子进程,由子进程来调用:/bin/sh -c command来执行参数command所代表的命令,阻塞当前进程直到command命 令执行完毕. int sys ...

  4. (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  5. (十二) 一起学 Unix 环境高级编程 (APUE) 之 进程间通信(IPC)

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  6. 《UNIX环境高级编程(第3版)》

    <UNIX环境高级编程(第3版)> 基本信息 原书名:Advanced Programming in the UNIX Environment (3rd Edition) (Addison ...

  7. (十一) 一起学 Unix 环境高级编程 (APUE) 之 高级 IO

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  8. (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

  9. (六) 一起学 Unix 环境高级编程 (APUE) 之 进程控制

    . . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...

随机推荐

  1. C# TextBox 焦点

    TextBox焦点问题 1.失焦 KeyBoard.ClearFocus(); 存在一个问题,失去焦点之后,中文通过输入法依旧是可以输入的. 如果是中文文本框,按Enter失焦,同时禁止输入中文,可以 ...

  2. 605. Can Place Flowers

    Suppose you have a long flowerbed in which some of the plots are planted and some are not. However, ...

  3. SUSE11虚拟机安装与Oracle 11g安装

    SUSE11虚拟机安装与Oracle 11g安装 本文中所需所有参数均位于文末附录中 新建虚拟机,选择SUSE11 64位 启动虚拟机后,选择第二项安装 选择语言 跳过CD检查 选择全新安装 选择默认 ...

  4. 各种异常 及异常类和Object类

    Day05 异常 Object类 equals方法,用于比较两个对象是否相同,它其实就是使用两个对象的内存地址在比较.Object类中的equals方法内部使用的就是==比较运算符. 2. 描述人这个 ...

  5. 服务器&阵列卡&组raid 5

    清除raid信息后,机器将会读不到系统, 后面若进一步操作处理, raid信息有可能会被初始化掉,那么硬盘数据就有可能会被清空, 导致数据丢失, 否则如果只是清除raid信息,重做raid是可以还原系 ...

  6. 解决Error: ENOENT: no such file or directory, scandir 'D:\IdeaWork\code-front-jet\node_modules\.npminstall\node-sass\3.7.0\node-sass\vendor'

    在使用npm安装node-sass的时候,可能会出现如下的报错: Error: ENOENT: no such file or directory, scandir 'D:\IdeaWork\code ...

  7. Python安装与环境变量的配置

    python下载: Python安装包下载地址:http://www.python.org/ 根据实际的操作系统,安装合适的安装版本. Python安装: 本文以python 2.7.8(64位)为例 ...

  8. Docker容器访问控制

    容器的访问控制,主要通过 Linux 上的 iptables 防火墙来进行管理和实现.iptables 是 Linux 上默认的防火墙软件,在大部分发行版中都自带. 容器访问外部网络 容器要想访问外部 ...

  9. Tomcat中的c3p0数据库连接池的释放

    一个项目通过c3p0获得连接池,相关代码如下: public class JdbcUtil { // 连接池的核心类 private static ComboPooledDataSource data ...

  10. React Native 4 for Android源码分析 一《JNI智能指针之介绍篇》

    文/ Tamic: http://blog.csdn.net/sk719887916/article/details/53455441 原文:http://blog.csdn.net/eewolf/a ...