所谓信号量,其实就是一个数字。内核给这个数字赋予一定的含义,让它等于不同的值时所表示的意义不同。这样就可以用它来标示某种资源是否正被使用。信号的分类其实挺多的,主要还是二值和计数器。这里讨论二值

现在有个文件,有两个进程要同时访问它。进程A 要往里面写入 "Math class is cancel",进程B 要往里面写入“English test”。正常情况下这两个信息会被完整的写入文件中。但是如果进程A写到"Math class" 就暂停,接着B进程就开始写“English test”,最后进程A继续写剩下的“is cancel ”,那文件最后的结果就是“Math class English test is cancel”。结果显然错的离谱。究其错误的原因其实很简单,两个进程在同时公用一个资源但是又没有一种机制来控制访问的先后顺序。因为Linux 是一个多任务的系统,这中资源被多个任务同时访问的情况是非常普遍的。我们需要一种机制来控制资源能够被有序的访问。信号量就是一种实现。

信号量互斥的实现机制简单描述如下:

让两个进程在真正写入数据之前先测试信号量sig。当进程A要写入文件时,它先测试信号量sig,如果信号量sig 等于1,表示这个文件没有其他进程再使用,那么它就将这个信号量减1 让它等于0,接着直接写数据到这个文件。但是当进程B测试信号量sig 时发现它等于0 ,表示有进程在使用它,那么内核就让进程B挂起,当信号量的值被置为1时它才能继续执行写入操作。、

描述完信号量的机制就可以讨论Linux内核对于信号量的实现。

事实上linux内核关于信号量的接口还是很简洁的。就三个函数:

int semget(key_t key, int num_sems, int sem_flags);
int semop(int semid, struct sembuf *sops, size_t ops_num);

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

semget函数

这个函数的功能是 创建/打开一个信号量集合,所谓集合其实就相当于数组。一个进程可能与多种资源相关联,可以用多个信号量来控制这些资源的访问。可见Linux 内核提供的信号量集合的概念是合理的。下面讨论它的参数和返回值:

返回值很简单,就是一个整型数----信号量标识符,标识符是内核为每个打开了的信号量集合而分配的,访问某个信号量集合就得靠它了(类比文件编程里的文件描述符)。key参数:键值。内核为所有的信号量集合维护了不同的键值,不管信号量集合是否被打开,这个键值都存在。键值其实就相当于文件名,但是键值是个整数,它可以自由指定,只是自由指定容易使得不同的信号量拥有相同的键值。因此内核提供了一个函数来分配键值:key_t ftok(const char *pathname, int proj_num);这个函数合成键值的机制简单描述下:

根据文件名pathname在内核中表示的数字以及proj_num共同合成一个键值key 并返回给调用者。num_sems参数:表明这个信号量集合的信号量个数。sem_flags参数:打开的标志,可以取值IPC_CREAT。当函数调用中有这个参数,并且键值指定的信号量集合不存在,那么这个函数就创建一个key 表示的信号量集合。

semop 函数

semop 函数用来信号量集合。事实上信号量集合的操作很简单,无非就是将信号量加一或者减一,来分别表示释放或者获取信号量。返回值除了表示操作的成败,没有什么意义。semid 参数:打开的信号量集合的标识符,从semget 返回。ops_num 参数:表示这个操作函数操作多少个信号量,因为信号量集合可能有多个信号量。 ops执行的结构体定义如下:

struct  sembuf

{

unsigned short   sem_num;//表明这个信号量在信号量集合中是哪一个

short       sem_op;     //表明操作类型    整数表明+1, 负数表明-1。事实上获取信号量和释放                                                    信号量就是在这里区别

short        sem_flg;

}

semctl 函数

semctl函数是在信号量上执行的多种操作。semid参数:表明要操作的信号量集合的标识符。semnum参数:表明要操作的信号量个数。command参数:表明要执行的命令。当我们要给信号量赋初值时可以令command == SETVAL,然后在省略参数给出要赋的值。

函数说明完了,下面给出一个简单的实例测试一下信号量互斥编程:

进程A:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h> int main()
{
int fd = ;
key_t key;
int semid;
struct sembuf sops; //创建并打开信号量
key = ftok("/home",);
semid = semget(key,,IPC_CREAT); semctl(semid,,SETVAL,);
/* 0.打开公示栏*/
fd = open("./board.txt",O_RDWR|O_APPEND); //获取信号量
sops.sem_num = ;
sops.sem_op = -;
semop(semid,&sops,); /* 1. 写入“数学课” */
write(fd,"Math class",); /* 2. 暂停 */
sleep(); /* 3. 写入“取消”*/
write(fd,"is cancel",); //释放信号量
sops.sem_num = ;
sops.sem_op = ;
semop(semid,&sops,); /* 4. 关闭公示栏 */
close(fd); return ;
}

进程B:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h> int main()
{
int fd = ;
key_t key;
int semid;
struct sembuf sops; /* 0.打开公示栏 */
fd = open("./board.txt",O_RDWR|O_APPEND); //打开信号量
key = ftok("/home",);
semid = semget(key,,IPC_CREAT); //获取信号量
sops.sem_num = ;
sops.sem_op = -;
semop(semid,&sops,); /* 1. 写入“英语课” */
write(fd,"Enclish exam",); //释放信号量
sops.sem_num = ;
sops.sem_op = ;
semop(semid,&sops,); /* 2. 关闭公示栏 */
close(fd); return ;
}

Linux 信号量互斥编程的更多相关文章

  1. Linux 信号量同步编程

    前一篇文章概述了Linux 系统中信号量互斥编程,这篇文章正好是前一篇的姊妹篇----信号量同步.说它们是姊妹篇是因为它们都是利用了内核的信号量机制实现了进程间的通信.因为两者所解决的问题不同,因此它 ...

  2. 转载自~浮云比翼:Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)

    Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)   介绍:什么是线程,线程的优点是什么 线程在Unix系统下,通常被称为轻量级的进程,线程虽然不是进程,但却可 ...

  3. 【linux草鞋应用编程系列】_3_ 进程间通信

    一.进程间通信        linux下面提供了多种进程间通信的方法, 管道.信号.信号量.消息队列.共享内存.套接字等.下面我们分别 介绍管道.信号量.消息队列.共享内存.        信号和套 ...

  4. 【linux草鞋应用编程系列】_1_ 开篇_系统调用IO接口与标准IO接口

    最近学习linux系统下的应用编程,参考书籍是那本称为神书的<Unix环境高级编程>,个人感觉神书不是写给草鞋看的,而是 写给大神看的,如果没有一定的基础那么看这本书可能会感到有些头重脚轻 ...

  5. Linux下的编程实战【转】

    一篇比较不错的文章, 降到了 makefile make , gcc编译器,GDB调试器, Linux文件系统,Linux文件API,.C语言库函数(C库函数的文件操作实际上是独立于具体的操作系统平台 ...

  6. Linux 高性能服务器编程——多线程编程

    问题聚焦:     在简单地介绍线程的基本知识之后,主要讨论三个方面的内容:    1 创建线程和结束线程:    2 读取和设置线程属性:    3 线程同步方式:POSIX信号量,互斥锁和条件变量 ...

  7. Linux 高性能服务器编程——多进程编程

    问题聚焦:     进程是Linux操作系统环境的基础.     本篇讨论以下几个内容,同时也是面试经常被问到的一些问题:     1 复制进程映像的fork系统调用和替换进程映像的exec系列系统调 ...

  8. Linux多线程服务器端编程

    目录 Linux多线程服务器端编程 线程安全的对象生命期管理 对象的销毁线程比较难 线程同步精要 借shared_ptr实现写时拷贝(copy-on-write) 多线程服务器的适用场合与常用编程模型 ...

  9. 【Linux】关于Linux的系统编程总结

    作者:李春港 出处:https://www.cnblogs.com/lcgbk/p/14673383.html 目录 系统编程 (一)进程 1.进程的概念 2.进程函数接口 (1)fork()在进程内 ...

随机推荐

  1. Bzoj 1975: [Sdoi2010]魔法猪学院 dijkstra,堆,A*,K短路

    1975: [Sdoi2010]魔法猪学院 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1357  Solved: 446[Submit][Statu ...

  2. fopen/fclose

    在操作文件之前要用fopen打开文件,操作完毕要用fclose关闭文件; 打开文件就是在操作系统中分配一些资源用于保存该文件的状态信息,并得到该文件的标示,以后用户程序就可以这个标志对文件做各种操作了 ...

  3. 你为什么学MSP430

    很清楚,很明白,目的性极强,你学这个,是为了竞赛,学51也是,学习FPGA也是,你压根打心眼里就没打算走硬件方向,原因不多说,尽管你还是喜欢硬件的,但是,现实是,一个人的精力是有限的,你啊,好好弄好你 ...

  4. 使用GruntJS链接与压缩多个JavaScript文件

    使用GruntJS链接与压缩多个JavaScript文件 自己写了个简单的HTML5 Canvas的图表库,可以支持饼图,折线图,散点图,盒子图 柱状图,同时支持鼠标提示,绘制过程动画效果等.最终我想 ...

  5. C#中A a=new B()的意义

    A a=new B()的意义 前提:A是B的父类. A a = new B(); 或 A a; B b=new B(); a=b; 这一句的过程是这样的, 1)创建一个类A的引用a 2)创建一个类B的 ...

  6. 实时的.NET程序错误监控产品Exceptionless开源了

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:实时的.NET程序错误监控产品Exceptionless开源了.

  7. CSS3实现兼容性的渐变背景效果

    一.CSS3实现兼容性渐变背景效果,兼容FF.chrome.IE 渐变效果,现在主流的浏览器FF.Chrome.Opera.IE8+都可以通过带有私有前缀的CSS3属性来轻松滴实现渐变效果,IE7及以 ...

  8. python实战--Http代理服务器

    打算好好深入研究下pytho的socket编程,那天看了这篇博文,http://www.apprk.com/archives/146,于是打算学习下,仿写了一下,发现写好还真不容易,中途出现很多问题, ...

  9. HTML里面Textarea换行总结

    近期碰到一个数据转来转去转到Textrea里面能否真正按行存放的问题,在这里总结一下:   问题描写叙述: 比方get数据到一个TextArea里面,如“AAA BBB”,想把这段文字在TextAre ...

  10. [Javascript] IIFE

    Javascript modules are a design pattern that allow you to encapsulate your code into smaller self ma ...