一.概述                                                   

System V信号量与System V消息队列不同。它不是用来在进程间传递数据。它主要是来同步进程的动作。

1.一个信号量是一个由内核维护的整数。其值被限制为大于或等于0。

2.可以在信号量上加上或减去一个数量。

3.当一个减操作把信号量减到小于0时,内核会阻塞调用进程。直到另一操作把信号恢复,阻塞才会解除。

4.常用的信号量是二进制信号量。即操作0和1来控制临界区。

二.函数接口                                           

1.创建或打开一个信号量

 #include <sys/sem.h>

 int semget(key_t key, int nsems, int semflg);

key和semflg跟消息队列一样,这里不再介绍,上面已给出消息队列的文章连接。

nsems:指定信号量数目,一般都是1。

2.控制信号量

 #include <sys/sem.h>

 int semctl(int semid, int semnum, int cmd, ...);

semid:semget()返回的信号量标识符。

semnum:信号量编号,如果是成组的信号量,就要用到它,否则是0。

cmd:控制信号量的命令。SETVAL初始化一个值,IPC_RMID删除信号量。

第四个参数是一个union semun结构。如果有的Linux版本头文件没有这个结构,需要自己定义:

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

3.改变信号量的值

 #include <sys/sem.h>

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

sops:指向一个sembuf结构,该结构成员如下:

unsigned short sem_num:信号量编号,如果不是一组信号,一般都为0。
short sem_op:对信号量加减操作,如:-1,+1,1。
short sem_flg:通常设置为SEM_UNDO。如果进程终止时没有释放该信号量,内核会释放它。

三.简单例子                                            

我们封装一个简单的二进制信号量,写2个小程序,一个只打印基数,一个只打印偶数,通过二进制信号量来控制它们按顺序打印1-10。

1.封装二进制信号量

 /**
  * @file binary_sem.h
  */

 #ifndef _BINARY_SEM_H_
 #define _BINARY_SEM_H_

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

 /* 设置信号量 */
 int sem_set(int sem_id);
 /* 增大信号量 */
 int sem_up(int sem_id);
 /* 减小信号量 */
 int sem_down(int sem_id);
 /* 删除信号量 */
 int sem_delete(int sem_id);

 #endif
 /**
  * @file binary_sem.c
  */

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

 #include "binary_sem.h"

 static union semun sem_union;
 static struct sembuf sem_buf;

 /* 设置信号量 */
 int sem_set(int sem_id)
 {
     sem_union.val = ;
     , SETVAL, sem_union) == -)
         ;
     ;
 }

 /* 改变信号量为1 */
 int sem_up(int sem_id)
 {
     sem_buf.sem_num = ;
     sem_buf.sem_flg = SEM_UNDO;
     sem_buf.sem_op = ;
     ) == -)
         ;
     ;
 }

 /* 信号量减1 */
 int sem_down(int sem_id)
 {
     sem_buf.sem_num = ;
     sem_buf.sem_flg = SEM_UNDO;
     sem_buf.sem_op = -;
     ) == -)
         ;
     ;
 }

 /* 删除信号量 */
 int sem_delete(int sem_id)
 {
     , IPC_RMID, sem_union) == -)
         ;
     ;
 }

2.打印基数的程序

 /**
  * @file sem1.c
  */

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <sys/sem.h>
 #include <unistd.h>

 #include "binary_sem.h"

 #define SEM_KEY 7788

 void err_exit(const char *err_msg)
 {
     printf("error: %s\n", err_msg);
     exit();
 }

 int main(int argc, const char *argv[])
 {
     int sem_id, i;

     /* 创建信号 */
     ,  | IPC_CREAT)) == -)
         err_exit("semget()");

     /* 初始化信号为1 */
     )
         err_exit("sem_set()");

     ; i < ; i += )
     {
         /* 信号减一 */
         )
             err_exit("sem_down()");

         sleep();
         printf(], i);

         /* 信号加一 */
         )
             err_exit("sem_up()");

         sleep();
     }
     ;
 }

对信号量加减操作之间的代码就是临界区。程序第39行的sleep()是为了有足够的时间来允许第二个程序,46行的sleep()是尽量让其他程序来获取信号量。

3.只打印偶数的程序

 /**
  * @file sem2.c
  */

 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/sem.h>

 #include "binary_sem.h"

 #define SEM_KEY 7788

 void err_exit(const char *err_msg)
 {
     printf("error: %s\n", err_msg);
     exit();
 }

 int main(int argc, const char *argv[])
 {
     int sem_id, i;

     /* 创建信号 */
     ,  | IPC_CREAT)) == -)
         err_exit("semget()");

     ; i <= ; i += )
     {
         /* 信号减一 */
         )
             err_exit("sem_down()");

         printf(], i);

         /* 信号加一 */
         )
             err_exit("sem_up()");

         sleep();
     }
     ;
 }

四.实验                                                  

1.为了测试方便,上面2个程序的key统一用一个值为7788的宏来指定。

2.两个程序执行的流程:sem1初始化一个为1的信号量,进入循环后对信号执行减一,并进入临界区。休眠3秒的时间我执行第二个程序sem2,sem2进入循环后也执行减一操作,但此时信号已被sem1减为0,此时内核会阻塞sem1的操作,因为再减就小于0了。回到sem1,3秒过后,打印基数,并把信号重置为1,离开临界区,休眠1秒。此时内核发现信号是1,可以执行减操作,内核会对sem2放行,sem2进入临界区打印偶数。刚刚休眠1秒的sem1再次进入临界区,发现信号量被sem2减到了0,此时被内核阻塞,直到sem2重置信号量。如此反复!!!

最后:其实System V信号量的语义和API都比较复杂,有机会再探讨比它简单的POSIX信号量。

System V IPC(2)-信号量的更多相关文章

  1. System V IPC 之信号量

    本文继<System V IPC 之共享内存>之后接着介绍 System V IPC 的信号量编程.在开始正式的内容前让我们先概要的了解一下 Linux 中信号量的分类. 信号量的分类 在 ...

  2. Linux 系统编程 学习:05-进程间通信2:System V IPC(2)

    Linux 系统编程 学习:05-进程间通信2:System V IPC(2) 背景 上一讲 进程间通信:System V IPC(1)中,我们介绍了System IPC中有关消息队列.共享内存的概念 ...

  3. 线程同步、信号量、system v IPC

    一.线程同步 条件变量 什么是条件变量? 线程A等待某个条件成立,条件成立,线程A才继续向下执行.线程B的执行使条件成立,条件成立以后唤醒线程A,以继续执行.这个条件就是条件变量. pthread_c ...

  4. 第3章 System V IPC

    3.1 概述 System V IPC 包含:System V消息队列.System V信号量.System V共享内存. 3.2 key_t 键和 ftok函数 这三种类型的System V IPC ...

  5. 《Unix网络编程》卷2 读书笔记 第3章- System V IPC

    1. 概述 三种类型的System V IPC:System V 消息队列.System V 信号量.System V 共享内存区 System V IPC在访问它们的函数和内核为它们维护的信息上共享 ...

  6. 从并发处理谈PHP进程间通信(二)System V IPC

    .container { margin-right: auto; margin-left: auto; padding-left: 15px; padding-right: 15px } .conta ...

  7. System V IPC 之共享内存

    IPC 是进程间通信(Interprocess Communication)的缩写,通常指允许用户态进程执行系列操作的一组机制: 通过信号量与其他进程进行同步 向其他进程发送消息或者从其他进程接收消息 ...

  8. System V IPC 之消息队列

    消息队列和共享内存.信号量一样,同属 System V IPC 通信机制.消息队列是一系列连续排列的消息,保存在内核中,通过消息队列的引用标识符来访问.使用消息队列的好处是对每个消息指定了特定消息类型 ...

  9. 四十九、进程间通信——System V IPC 之消息队列

    49.1 System V IPC 介绍 49.1.1 System V IPC 概述 UNIX 系统存在信号.管道和命名管道等基本进程间通讯机制 System V 引入了三种高级进程间通信机制 消息 ...

随机推荐

  1. Eclipse的SVN插件提示:验证验证位置时发生错误:"Unable to load default SVN Client“解决

    这个原因是你的机器上没有 JAVAHL 这个包, 这个是另外的一个开源组件, 所以, 在trigis的svn插件发行版里面没有这个东西,下载装上就是, 这个包在不同的系统上, 有不同的情况...详情见 ...

  2. JBox - 模态窗口,工具提示和消息 jQuery 插件

    jBox 是一个强大而灵活的 jQuery 插件,可以帮助实现模态窗口,工具提示,通知和更多的功能.你可以使用 jQuery 选择器轻松地添加工具提示效果到元素上,您可以以同样的方式设置模态窗口.该库 ...

  3. javascript笔记图

    1.this 2.对象 3.继承 4.跨域 5.事件 6.基础

  4. ReactNative ScrollView或ListView头部莫名其妙多了20px

    之前在还没有加TabBarIOS时,ScrollView一直是好好的,然后随着深入,需要做其他tab页面的时候问题来了,当我把首页加入TabBarIOS.Item时..我首页中的ScrollView头 ...

  5. JavaScript语言精粹学习笔记

    0.JavaScript的简单数据类型包括数字.字符创.布尔值(true/false).null和undefined值,其它值都是对象. 1.JavaScript只有一个数字类型,它在内部被表示为64 ...

  6. 初试钓鱼工具Weeman+DNS欺骗的使用

    下午无聊再网上闲逛随意看了下,自己做了一次测试,目前最新的版本是1.6.Weeman是一款运行在Python环境下的钓鱼渗透测试工具 但这款工具简单易用,安装简单,可伪造HTML页面等等...网上看了 ...

  7. 发布App,赢iPad mini + 美金100$ - Autodesk Exchange 应用程序发布竞赛

    开发牛人们,送你个iPad mini要不要,Autodesk Exchange应用程序发布竞赛开始了. 摘要版: 在2014年9月30日午夜前提交到Autodesk Exchange 应用程序商店上, ...

  8. 见见面、聊聊天 - 5月22日晚7点Meetup,三里屯绿树旁酒吧,畅谈云技术和应用

    总是邮件.QQ什么的线上聊,让我们见面吧,不怕见光死,呵呵.   我和同事会先抛砖引玉,给大家介绍一下Autodesk几款最新的云技术和解决方案,然后大家就可畅所欲言,自由交流.来自五湖四海的人,为了 ...

  9. 几个有用的JSON工具

    好久没写博客了,这里都要长草了:) 这几天研究PLM360 REST API和Infraworks REST API,一天到晚和JSON打交道,发现这几个小工具非常好用,推荐给大家. 第0个,大名鼎鼎 ...

  10. 转:jquery选择器总结

    原文地址:http://www.cnblogs.com/onlys/articles/jQuery.html jQuery 的选择器可谓之强大无比,这里简单地总结一下常用的元素查找方法   $(&qu ...