信号量是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语。有三种类型:Posix有名信号量,使用Posix IPC名字标识。Posix基于内存的信号量,存放在共享内存区中;System V信号量。在内核中维护。

这三种信号量都可用于进程间或线程间的同步。

图1 由两个进程使用的一个二值信号量

图2 由两个进程使用的一个Posix有名二值信号量

图3 由一个进程内的两个线程共享的基于内存的信号量

一个进程可以在某个信号量上运行的三种操作:

1、创建一个信号量,这要求调用者指定初始值,对于二值信号量来说。它一般是1,也但是0。

2、等待一个信号量,该操作会測试这个信号量的值。假设小于0,就堵塞。也称为P操作。

3、挂出一个信号量。该操作将信号量的值加1,也称为V操作。

信号量、相互排斥锁和条件变量之间的三个差异:

1、相互排斥锁必须总是给它上锁的线程解锁,信号量的挂出却不必由运行过它的等待操作的同一线程运行。

2、相互排斥锁要么被锁住,要么被解开。

3、既然信号量有一个与之关联的状态。那么信号量挂出操作总是被记住。

然而当向一个条件变量发送信号时。假设没有线程等待在该条件变量上。信号丢失。

Posix提供两类信号量:有名信号量和基于内存的信号量(也称无名信号量)。

使用函数例如以下:

#include <semaphore.h>
/*sem_open创建一个新的有名信号量或打开一个已存在的有名信号量,value參数指定信号量的初始值。返回值是一个指向某个sem_t数据类型的指针,用作其它函数的參数*/
sem_t *sem_open(const char *name, int oflag, .../*mode_t mode, unsigned int value*/);
int sem_close(sem_t *sem); /*一个进程终止时,内核对其上仍打开着的全部信号量自己主动运行关闭操作*/
int sem_unlink(const char *name); /*sem_unlink函数:当引用计数大于0时,name就能从文件系统中删除,然而信号量的析构却要等到最后一个sem_close发生时为止*/
int sem_wait(sem_t *sem); /*測试所指定信号量的值,大于0。将它减1并返回,等于0,调用线程休眠。直到该值大于0,将它减1,函数随后返回*/
int sem_trywait(sem_t *sem); /*所指定信号量值为0时,不休眠,而是返回一个EAGAIN错误*/
int sem_post(sem_t *sem);
int sem_getvalue(sem_t *sem, int *valp);/* 由valp指向的整数中返回所指定信号量的当前值。 */

semcreate程序:

#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h> #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) int
main(int argc, char **argv)
{
int c, flags;
sem_t *sem;
unsigned int value; flags = O_RDWR | O_CREAT;
value = 1; while((c = getopt(argc, argv, "ei:")) != -1){
switch(c){
case 'e':
flags |= O_EXCL;
case 'i':
value = atoi(optarg);
break;
}
} if(optind != argc - 1){
printf("usage:semcreate [-e] [-i initalvalue] <name>\n");
return -1;
}
sem = sem_open(argv[optind], flags, FILE_MODE, value); sem_close(sem);
exit(0);
}

semunlink程序:

#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int
main(int argc, char **argv)
{
if(argc != 2){
printf("usage:semunlink <name>.\n");
return -1;
} sem_unlink(argv[1]);
exit(0);
}

semgetvalue程序:

#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int
main(int argc, char **argv)
{
sem_t *sem;
int val; if(argc != 2){
printf("usage:semgetvalue <name>.\n");
return -1;
} sem = sem_open(argv[1], 0);
sem_getvalue(sem, &val);
printf("value = %d\n", val); exit(0);
}

semwait程序:

#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int
main(int argc, char **argv)
{
sem_t *sem;
int val; if(argc != 2){
printf("usage: semwait <name>");
return -1;
} sem = sem_open(argv[1], 0);
sem_wait(sem);
sem_getvalue(sem, &val);
printf("pid %ld has semaphore, value = %d\n", (long)getpid(), val); pause(); /*block until killed*/
exit(0);
}

sempost程序:

#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> int
main(int argc, char **argv)
{
sem_t *sem;
int val; if(argc != 2){
printf("usage:sempost <name>\n");
return -1;
} sem = sem_open(argv[1], 0);
sem_post(sem);
sem_getvalue(sem, &val);
printf("value = %d\n", val); exit(0);
}

Posix基于内存的信号量,由应用程序分配信号量的内存空间(也就是分配一个sem_t数据类型的内存空间),然后由系统初始化它们的值。

#include <stmaphore.h>
int sem_init(sem_t *sem, int shared, unsigned int value); /*出错返回-1*/
int sem_destroy(sem_t *sem); <span style="white-space:pre"> </span>/*成功返回0,出错返回-1*/

基于内存的信号量是由sem_init初始化的,sem參数指向应用程序必须分配的sem_t变量。假设shared为0,那么待初始化的信号量是在同一进程的各个线程间共享的,否则该信号量是在进程间共享的。

当不须要使用与有名信号量关联的名字时,可改用基于内存的信号量。

彼此无亲缘关系的不同进程须要使用信号量时,通常使用有名信号量。其名字就是各个进程标识信号量的手段。基于内存信号量至少具有进程持续性,然而它们真正的持续性却取决于存放信号量的内存区的类型。

仅仅要含有某个基于内存信号量的内存区保持有效,该信号量就一直存在。

进程间共享信号量

进程间共享基于内存信号量的规则非常easy:信号量本身必须驻留在由全部希望共享它的进程所共享的内存区中,并且sem_init的第二个參数必须是1。

有名信号量,不同进程总是可以訪问同一个有名信号量。仅仅要它们在调用sem_open时指定同样的名字就可以。

信号量限制

Posix定义了两个信号量限制:

SEM_NSEMS_MAX 一个进程可同一时候打开着的最大信号数

SEM_VALUE_MAX 一个信号量的最大值

这两个常值定义在<unistd.h>头文件里。可在运行时通过sysconf函数获取。

Linux环境编程之同步(四):Posix信号量的更多相关文章

  1. Linux环境编程之同步(二):条件变量

    相互排斥锁用于上锁,条件变量则用于等待.条件变量是类型为pthread_cond_t的变量.一般使用例如以下函数: #include <pthread.h> int pthread_con ...

  2. Linux环境编程之同步(三):读写锁

    概述 相互排斥锁把试图进入我们称之为临界区的全部其它线程都堵塞住.该临界区通常涉及对由这些线程共享一个或多个数据的訪问或更新.读写锁在获取读写锁用于读某个数据和获取读写锁用于写直接作差别. 读写锁的分 ...

  3. Linux环境编程相关的文章

    Linux环境编程相关的文章 好几年没有接触Linux环境下编程了,好多东西都有点生疏了.趁着现在有空打算把相关的一些技能重拾一下,顺手写一些相关的文章加深印象. 因为不是写书,也受到许多外部因素限制 ...

  4. <转>Linux环境进程间通信--信号灯(四)

    http://www.ibm.com/developerworks/cn/linux/l-ipc/part4/ 一.信号灯概述 信号灯与其他进程间通信方式不大相同,它主要提供对进程间共享资源访问控制机 ...

  5. linux系统编程之(一) 信号量

    信号量 一.什么是信号量 信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有. 信号量的值为正的时候,说明它空闲.所测试的线程可以锁定而使用它.若为0,说明 它被占用,测 ...

  6. Linux系统编程 —线程同步概念

    同步概念 同步,指对在一个系统中所发生的事件之间进行协调,在时间上出现一致性与统一化的现象. 但是,对于不同行业,对于同步的理解略有不同.比如:设备同步,是指在两个设备之间规定一个共同的时间参考:数据 ...

  7. Linux 环境编程:dirfd参数 有关解析

    背景 在Unix环境编程中,系统提供了很多以at结尾的函数,如openat.fstatat等,而这类函数通常有一个特点,就是形参列表中多了int dirfd 例如: int open(const ch ...

  8. Linux c编程:同步属性

    就像线程具有属性一样,线程的同步对象(如互斥量.读写锁.条件变量.自旋锁和屏障)也有属性 1.互斥量属性 用pthread_mutexattr_init初始化pthread_mutexattr_t结构 ...

  9. linux系统编程--线程同步

    同步概念 所谓同步,即同时起步,协调一致.不同的对象,对“同步”的理解方式略有不同. 如,设备同步,是指在两个设备之间规定一个共同的时间参考: 数据库同步,是指让两个或多个数据库内容保持一致,或者按需 ...

随机推荐

  1. DB开发之大数据量高并发的数据库优化

    一.数据库结构的设计 如果不能设计一个合理的数据库模型,不仅会增加客户端和服务器段程序的编程和维护的难度,而且将会影响系统实际运行的性能.所以,在一个系统开始实施之前,完备的数据库模型的设计是必须的. ...

  2. 微信JS支付代码_前端调用微信支付接口

    转自:http://dditblog.com/itshare_553.html 跟大家分享一段微信支付的js代码片段.V3版的微信支付没有paySignKey参数.基本上是直接复制就可以使用了.改一改 ...

  3. JS实现弹出层效果

    很多时候我们想去某某网站干点什么的时候,就会让我们先注册登录后才可以访问内容,而现在很多网站注册登录的时候都会有一种遮罩层的效果,就是背景是带有透明度的黑色遮罩,盖满整个网站,然后登录框弹出固定在屏幕 ...

  4. Python - TypeError: unicode argument expected, got 'str'

    参考:TypeError: unicode argument expected, got 'str' Python代码: from io import StringIO def main(): f = ...

  5. SDN前瞻 传统网络架构的危机:危机“四”起

    本文基于SDN导论的视频而成:SDN导论 在网络发展速度如此之快的今天,传统网络的架构充满了危机,主要有这四个问题(3+1). 1)传统网络的部署和管理 非常困难 2)分布式网络架构凸显瓶颈 3)流量 ...

  6. 2012NOIP模拟试题

    做的时候觉得这套题好简单,结果一看发现是2012年的模拟题,估计就是普及+的难度吧,AK无压力 总结 第一题状压我智障的调了好几分钟,因为我的最终状态写的1<<n,智障了 第三题的dfs调 ...

  7. Linux 用户和组的 添加/删除

    1.建用户:adduser phpq //新建phpq用户passwd phpq //给phpq用户设置密码 2.建工作组groupadd test //新建test工作组 3.新建用户同时增加工作组 ...

  8. BZOJ 2594 【WC2006】 水管局长数据加强版

    题目链接:水管局长数据加强版 好久没写博客了…… 上次考试的时候写了一发LCT,但是写挂了……突然意识到我已经很久没有写过LCT了,于是今天找了道题来练练手. 首先,LCT这里不讲.这道题要求支持动态 ...

  9. python find 返回元素的索引

    As it turns out, there is a string method named find that is remarkably similar to the function we w ...

  10. bootstrap.min.css.map HTTP/1.1" 404 1699

    在做一个jsp练习的时候遇到引入bootstrap.css的时候出现了URL:bootstrap.min.css.map 404的错误. 解决办法:删除bootstrap.min.css文件内容最后一 ...