Linux 信号量互斥编程
所谓信号量,其实就是一个数字。内核给这个数字赋予一定的含义,让它等于不同的值时所表示的意义不同。这样就可以用它来标示某种资源是否正被使用。信号的分类其实挺多的,主要还是二值和计数器。这里讨论二值
现在有个文件,有两个进程要同时访问它。进程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 信号量互斥编程的更多相关文章
- Linux 信号量同步编程
前一篇文章概述了Linux 系统中信号量互斥编程,这篇文章正好是前一篇的姊妹篇----信号量同步.说它们是姊妹篇是因为它们都是利用了内核的信号量机制实现了进程间的通信.因为两者所解决的问题不同,因此它 ...
- 转载自~浮云比翼:Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥)
Step by Step:Linux C多线程编程入门(基本API及多线程的同步与互斥) 介绍:什么是线程,线程的优点是什么 线程在Unix系统下,通常被称为轻量级的进程,线程虽然不是进程,但却可 ...
- 【linux草鞋应用编程系列】_3_ 进程间通信
一.进程间通信 linux下面提供了多种进程间通信的方法, 管道.信号.信号量.消息队列.共享内存.套接字等.下面我们分别 介绍管道.信号量.消息队列.共享内存. 信号和套 ...
- 【linux草鞋应用编程系列】_1_ 开篇_系统调用IO接口与标准IO接口
最近学习linux系统下的应用编程,参考书籍是那本称为神书的<Unix环境高级编程>,个人感觉神书不是写给草鞋看的,而是 写给大神看的,如果没有一定的基础那么看这本书可能会感到有些头重脚轻 ...
- Linux下的编程实战【转】
一篇比较不错的文章, 降到了 makefile make , gcc编译器,GDB调试器, Linux文件系统,Linux文件API,.C语言库函数(C库函数的文件操作实际上是独立于具体的操作系统平台 ...
- Linux 高性能服务器编程——多线程编程
问题聚焦: 在简单地介绍线程的基本知识之后,主要讨论三个方面的内容: 1 创建线程和结束线程: 2 读取和设置线程属性: 3 线程同步方式:POSIX信号量,互斥锁和条件变量 ...
- Linux 高性能服务器编程——多进程编程
问题聚焦: 进程是Linux操作系统环境的基础. 本篇讨论以下几个内容,同时也是面试经常被问到的一些问题: 1 复制进程映像的fork系统调用和替换进程映像的exec系列系统调 ...
- Linux多线程服务器端编程
目录 Linux多线程服务器端编程 线程安全的对象生命期管理 对象的销毁线程比较难 线程同步精要 借shared_ptr实现写时拷贝(copy-on-write) 多线程服务器的适用场合与常用编程模型 ...
- 【Linux】关于Linux的系统编程总结
作者:李春港 出处:https://www.cnblogs.com/lcgbk/p/14673383.html 目录 系统编程 (一)进程 1.进程的概念 2.进程函数接口 (1)fork()在进程内 ...
随机推荐
- MD5算法原理
//消息摘要:将任意长度的字符数组处理成定长的字符数组,用于确保原字符串不被修改, //也可以用做密码确认,如果密码一致,则MD5产生后的值必然一致,否则不相同 public class DataUt ...
- HW4.26
public class Solution { public static void main(String[] args) { double sum; double item; for(int i ...
- 【ACM/ICPC2013】二分图匹配专题
前言:居然三天没有更新了..我的效率实在太低,每天都用各种各样的理由拖延,太差了!昨天的contest依旧不能让人满意,解出的三题都是队友A的,我又卖了一次萌..好吧废话不多说,今天我要纪录的是二分图 ...
- Git(一)环境搭建 + 常用命令
上周研究了一下 Git,简单的使用了一下,个人感觉相对 SVN 来说还是有一定学习成本的,这次记录一些自己的学习过程以及常用的命令. 在学习的过程中,同事推荐了一个前辈写的教程([传送门]:Git教程 ...
- Android——C语言、JNI与低层调用
JNI java native interface c的基本数据类型 int:32位,能表示的数字是2的32次方个 最高位用来表示符号位,那么还剩下31位可以表示数值,所以能表示的数字就是2的31次方 ...
- PL/SQL:使用pragma restrict_references限制包权限
在看别人的代码的时候.发现了例如以下的编译指令. pragma restrict_references(get_attribute_name, wnds); get_attribute_name是一个 ...
- hdu 1317 XYZZY【Bellheman_ford 判断正环小应用】
链接: http://acm.hdu.edu.cn/showproblem.php?pid=1317 http://acm.hust.edu.cn/vjudge/contest/view.action ...
- qt 与mysql建立交互式连接
void QSqlDatabase::setConnectOptions(const QString & options = QString())Sets database-specific ...
- SourceTree - 好用的 Git / Mercurial GUI 管理工具 for Mac OS X
Git 是免費.開放源碼的分散式版本控制系統,從小專案到非常大的專案,都可以很快速.有效地管理. 對程式設計師來說,一定要熟記 git 指令的用法,在終端機下操作 git 是必備的基本技能.(其他的 ...
- NDK开发之访问域
Java有两类域,实例域和静态域.类的每个实例都有自己的实例域副本,而一个类的所有实例共享一个静态域(Java SE基础). JNI提供了相应的函数来访问这两类域,总体步骤是这样的: 1.通过对象引用 ...