码迷,mamicode.com
首页 > 其他好文 > 详细

semctl semget semop 函数系列构成的 信号量

时间:2015-06-10 07:37:54      阅读:168      评论:0      收藏:0      [点我收藏+]

标签:

semctl semget semop 函数系列构成的 信号量

信号量原语

简介

信号量是由 Dijkstra 提出的解决多进程沟通和并发编程问题的特殊变量,这种变量只能取自然数,而且只支持两种操作: wait & signal 。它主要处理多个进程访问资源的问题,通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域,而临界区域是指执行数据更新的代码需要独占式地执行。

实现方式

首先创建一个信号量 SV,并且使用一个整数唯一的标识信号量(这个标识量是跨越进程存在的,即在不同的进程中同一个信号量也能唯一的标识该事件)。只有两种 一种是 wait 操作,一种是 signal 操作,不过为了避免和linux的概念重复,又被称为 P 操作 和 V 操作

  • P(SV) :如果 SV 大于 0,那么 SV 的值 减一,这里的值指的是信号量所带的值,而不是标识信号量的整数,就和结构体名和结构体的内的一个变量一样,减的是变量。如果是SV==0,那么就挂起该进程的执行

  • V(SV):如果有其他进程由 因等待SV 挂起,那么 激活给他,如果没有 那么就 SV 加 一

上面很难理解对吧,举个例子吧。
我有两个进程 A & B,他们分想访问资源 C (访问过程的代码为关键代码),利用 信号量 来保证同时只有唯一的一个。比如

  1. 开始时首先设置 SV 的值 为 1

  2. 假设 A 优先 走到 关键代码区域,它会执行 P(SV) ,根据上面的操作,他会减 1 ,同时执行关键的代码。

  3. 在 A 执行关键代码的时候,B运行到了关键代码出,执行 P(SV
    ),它会则会挂起该进程,直到 A 执行完关键代码,并且 执行了 V(SV)

但必须强调的是 P(SV),V(SV ),都必须是原子操作。是由
sys/sem.h 的定义的函数实现的。

有些分类方式业在这提一下啊
信号量按其用途可分为两种:
􀁺 公用信号量:联系一组并发进程,相关的进程均可在此信号量上执行P 和V操作。初值常常为1,用于实现进程互斥。
􀁺 私有信号量:联系一组并发进程,仅允许此信号量拥有的进程执行P 操作,而其他相关进程可在其上施行V 操作。初值常常为0 或正整数,多用于并发进程同步。
信号量按其取值可分为两种:
􀁺 二元信号量:仅允许取值为0 和1,主要用于解决进程互斥问题。
􀁺 一般信号量:允许取值为非负整数,主要用于解决进程同步问题。

函数集

创建or 获得

int semget(key_t key, int num_sems, int sem_flags);  

第一个参数key是整数值(唯一非零),不相关的进程可以通过它访问一个信号量,它代表程序可能要使用的某个资源,程序对所有信号量的访问都是间接的,程序先通过调用semget函数并提供一个键,再由系统生成一个相应的信号标识符(semget函数的返回值),只有semget函数才直接使用信号量键,所有其他的信号量函数使用由semget函数返回的信号量标识符。如果多个程序使用相同的key值,key将负责协调工作。

第二个参数num_sems指定信号集中信号的个数
具体的值是根据你使用信号量的目的,如果你想要实现进程之间的互斥操作,设置为1 ,而如果想要实现多进程的同步问题,那么至少得大于一。在为零的情况下,是获取该信号量。

第三个参数sem_flags是一组标志,当想要当信号量不存在时创建一个新的信号量,可以和值IPC_CREAT做按位或操作。设置了IPC_CREAT标志后,即使给出的键是一个已有信号量的键,也不会产生错误。而IPC_CREAT | IPC_EXCL则可以创建一个新的,唯一的信号量,如果信号量已存在,返回一个错误。

semget函数成功返回一个相应信号标识符(非零),失败返回-1.

信号量操作

int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);  

它用来实现信号量的 P,V 操作,利用是的结stuct sembuf来指示操作内容

struct sembuf{  
    short sem_num;//除非使用一组信号量,否则它为0  
    short sem_op;//信号量在一次操作中需要改变的数据,通常是两个数,一个是-1,即P(等待)操作,  
                    //一个是+1,即V(发送信号)操作。  
    short sem_flg;//通常为SEM_UNDO,使操作系统跟踪信号,  
                    //并在进程没有释放该信号量而终止时,操作系统释放信号量  
};  

结构体中的变量含义为
sem_num : 指定操作信号量集中的第 sem_num+1 个信号量,一般设置为 0,表示操作第一个
sem_flag:
IPC_NOWAIT :设置信号量操作不等待
SEM_UNDO : 选项会让内核记录一个与调用进程相关的UNDO记录,如果该进程崩溃,则根据这个进程的UNDO记录自动恢复相应信号量的计数值
sem_op : 表示 操作信号量的方式,实现 P | V 的操作

sem_op 意义
大于0 将 sem_val + opt ,但要求有写权限
等于 0 在没有设置 IPC_NOWAIT 的情况下,会挂起 等待 sem_val==0的情况发生,发生则立即返。但设置的话,就会立即返回错误信息EAGAIN
小于 0 在没有设置 IPC_NOWAIT的情况下,会等待 sem_op的绝对值小于 等于sem_val的值,小于的话,就减去它,并且放回,设置的话,与 等于0 的情况基本一致

等于 0 一般被称为 等待 0 ,而小于 0 则可以称为 等待可减

信号量设置

int semctl(int sem_id, int sem_num, int command, ...);  

该函数用于对信号量直接设置
sem_id 为信号量级标识
sem_um 指定被操作信号量在信号量集中的编号
command 为操作命令
技术分享
而... 代表可扩展参数,推荐使用一下啊的结构体填充

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

而该结构体中的 semid_ds 和 seminfo 的结构体,seminfo 表示信号量系统资源配置信息,semid_ds则是一个内核结构体,在 semget 函数创建信号量时,被初始化和关联
的具体信息可以去man 一下 该函数,

semctl semget semop 函数系列构成的 信号量

标签:

原文地址:http://www.cnblogs.com/dilidingzhi/p/4565021.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!