linux Posix 信号量 二
一、Posix信号量
1.Posix信号量分为两种:
1. 有名信号量:使用Posix IPC名字标识(有名信号量总是既可用于线程间的同步,又可以用于进程间的同步)
2. 内存信号量:存放在共享内存区中(基于内存的信号量则必须在创建时指定成是否在进程间共享,且在所有进程的共享内存区,具有随进程的持续性)
Posix信号量不必在内核中维护(System V信号量由内核维护),由可能为路径名的名字来标识。
(Posix信号量更常用于进程间同步,互斥锁常用于线程间同步)
2.基本操作:
1. 创建(create):指定初始值。
2. 等待(wait):如果值小于等于0则阻塞,否则将其减一,又称P操作。
3. 挂出(post):将信号量的值加1,加后如果值大于0,则唤醒一个阻塞在等待上的线程,又称V操作。
二值信号量可用于互斥,就像互斥锁一样。但互斥锁必须由锁住它的线程解锁,信号量的挂出却不必由执行过等待的同一线程执行。
信号量的wait和post与条件变量的wait和signal类似,区别是:因为永久的改变了信号量的值,信号量的操作总被记住(会影响到后续的操作);条件变量的signal如果没有线程在等待,该信号将丢失(对后续操作没有影响)。
互斥锁是为上锁而优化的,条件变量是为等待优化的,信号量既可以上锁也可以等待,因此开销更大。
3.Posix信号量操作
|
有名信号量: |
内存信号量: |
|
sem_open |
sem_init:需要指定是否共享 |
|
sem_wait:原子的“测试并减1”操作 |
|
|
sem_trywait |
|
|
sem_post:同步技巧中唯一能在信号处理函数内安全调用的操作 |
|
|
sem_getvalue |
|
|
sem_close |
sem_destroy |
|
sem_unlink |
|
即使当前没有进程打开信号量,它的值仍然保持,因此Posix有名信号量至少是随内核持续的。
在父进程中打开的任何信号量,fork后在子进程中仍打开。
关于posix有名信号量使用的几点注意:
1、有名信号量使用sem_unlink从系统中删除。每个信号量有一个引用计数器记录当前的打开次数,sem_unlink必须等待这个数为0时才能把name所指的信号量从文件系统中删除。也就是要等待最后一个sem_close发生。
2、彼此无亲缘关系的进程间需使用信号量时,一般用有名信号量。如果不需要使用关联名字时,可改用内存信号量。
内存信号量需要放在共享内存区中,并由sem_init函数初始化为shared状态才能被不同进程使用,这种情况下它的持续性与共享内存区相同。sem_init总是初始化信号量的值,因此,对于一个给定的信号量,必须小心保证只调用sem_init一次。
3、我们可以用sem_wait来申请共享资源,sem_wait函数可以测试所指定信号量的值,如果该值大于0,那就将它减1并立即返回。我们就可以使用申请来的共享资源了。如果该值等于0,调用线程就被进入睡眠状态,直到该值变为大于0,这时再将它减1,函数随后返回。sem_wait操作必须是原子的。sem_wait和sem_trywait的差别是:当所指定信号量的值已经是0时,后者并不将调用线程投入睡眠。相反,它返回一个EAGAIN错误。
当一个线程使用完某个信号量时,它应该调用sem_post来告诉系统申请的资源已经用完。本函数和sem_wait函数的功能正好相反,它把所指定的信号量的值加1,然后唤醒正在等待该信号量值变为正数的任意线程。
4、.Posix有名信号量的值是随内核持续的。也就是说,一个进程创建了一个信号量,这个进程结束后,这个信号量还存在,并且信号量的值也不会改变。
5、当持有某个信号量锁的进程没有释放它就终止时,内核并不给该信号量解锁。
posix有名信号量应用于多线程
|
#include <semaphore.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <thread.h> void *thread_function(void *arg); /*线程入口函数*/ void print(pid_t); /*共享资源函数*/ sem_t *sem; /*定义Posix有名信号量*/ int val; /*定义信号量当前值*/ int main(int argc,char *argv[]) { int n=0; if(argc!=2) { printf(“please input a file name!\n”); exit(1); } sem=sem_open(argv[1],O_CREAT,0644,3); /*打开一个信号量*/ while(n++<5) /*循环创建5个子线程,使它们同步运行*/ { if((pthread_create(&a_thread,NULL,thread_function,NULL))!=0) { perror(“Thread creation failed”); exit(1); } } pthread_join(a_thread,NULL); sem_close(bin_sem); sem_unlink(argv[1]); } void *thread_function(void *arg) { sem_wait(sem); /*申请信号量*/ print(); /*调用共享代码段*/ sleep(1); sem_post(sem); /*释放信号量*/ printf(“I’m finished,my tid is %d\n”,pthread_self()); } void print() { printf(“I get it,my tid is %d\n”,pthread_self()); sem_getvalue(sem,&val); printf(“Now the value have %d\n”,val); } |
程序用循环的方法建立5个线程,然后让它们调用同一个线程处理函数thread_function,在函数里我们利用信号量来限制访问共享资源的线程数。共享资源我们用print函数来代表,在真正编程中它有可以是一个终端设备(如打印机)或是一段有实际意义的代码。
linux Posix 信号量 二的更多相关文章
- linux POSIX 信号量介绍
信号量一.什么是信号量信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)使用.多线程可以同时运行多个线程函数完成功能,但是对于共享数据如果不加以锁定,随意改变共享数据的值会发生 ...
- linux Posix 信号量 一
信号量是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语. linux提供两种信号量,“内核信号量”和“用户态进程信号量”,“用户态信号量”又分为“Posix”,“System V”信号 ...
- linux POSIX信号量
POSIX信号量机制是3种IPC机制之一,3种IPC机制源于POSIX.1的实时扩展. 创建一个新的命名信号量或者使用一个现有信号量 #include <fcntl.h> #include ...
- linux Posix 信号量 三 (经典例子)
本文将阐述一下信号量的作用及经典例子,当中包括“<越狱>寄信”,“家庭吃水果”,“五子棋”,“接力赛跑”,“读者写者”,“四方恋爱”等 首先,讲 semWait操作(P操作)和semSig ...
- Linux进程间通信IPC学习笔记之同步二(Posix 信号量)
Linux进程间通信IPC学习笔记之同步二(Posix 信号量)
- Linux进程同步之POSIX信号量
POSIX信号量是属于POSIX标准系统接口定义的实时扩展部分.在SUS(Single UNIX Specification)单一规范中,定义的XSI IPC中也同样定义了人们通常称为System V ...
- Linux环境编程之同步(四):Posix信号量
信号量是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语.有三种类型:Posix有名信号量,使用Posix IPC名字标识.Posix基于内存的信号量,存放在共享内存区中:System ...
- linux c编程:Posix信号量
POSIX信号量接口,意在解决XSI信号量接口的几个不足之处: POSIX信号量接口相比于XSI信号量接口,允许更高性能的实现. POSIX信号量接口简单易用:没有信号量集,其中一些接口模仿了我们熟悉 ...
- linux网络编程之posix信号量与互斥锁
继上次学习了posix线程之后,这次来讨论一下posix信号量与互斥锁相关的知识: 跟posix消息队列,共享内存的打开,关闭,删除操作一样,不过,上面的函数是对有名信号量进行操作,通过man帮助可以 ...
随机推荐
- 20145204《Java程序设计》第5周学习总结
20145204<Java程序设计>第5周学习总结 教材学习内容总结 语法与继承构架 我们之前接触到的C通常都是将程序流程和错误处理混在一起,在编写程序的时候必须考虑可能出现的错误并提前做 ...
- JS封装简单后代选择器
大概思路是这样的:通过判断传过来的参数是什么类型,如果是对象,那这里就是this(因为封装是自己用的,肯定不会随便乱传一个对象过来),如果是一个函数(匿名函数),那就是Dom加载(这里先不讲),如果是 ...
- Asynchronous Programming Using Delegates使用委托进行异步编程
http://msdn.microsoft.com/zh-cn/library/22t547yb(v=vs.110).aspx https://github.com/chucklu/Test/tree ...
- BZOJ 3676 【APIO2014】 回文串
题目链接:回文串 我终于也会回文自动机辣! 其实吗……我觉得回文自动机(听说这玩意儿叫\(PAM\))还是比较\(simple\)的……至少比\(SAM\)友善多了…… 所谓回文自动机,每个节点就代表 ...
- hdu 4348 To the moon 主席树区间更新
To the moon Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Prob ...
- [java]java String.split()函数的用法分析
转自:http://swiftlet.net/archives/709 一.在java.lang包中有String.split()方法的原型是: public String[] split(Strin ...
- 雷林鹏分享:Ruby 迭代器
Ruby 迭代器 迭代器是集合支持的方法.存储一组数据成员的对象称为集合.在 Ruby 中,数组和散列可以称之为集合. 迭代器返回集合的所有元素,一个接着一个.在这里我们将讨论两种迭代器,each 和 ...
- 雷林鹏分享:Ruby 多线程
Ruby 多线程 每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程. 线程是程序中一个单一的顺序控制流程,在单个程序中同时运行多个线程完成不同的工作,称为多线程. Ruby 中我们可以通 ...
- bzoj1025
题意: 找环 有多少种不同的排列 使排列数目为n 题解: 考虑dp f[i][j]表示前i个质数,和为j的方案数 然后转移一下即可 代码: #include<bits/stdc++.h> ...
- 基于Open XML 导出数据到Excel
数据导出的结果: 步骤1.新建一个Excel 文档,模板根据自己需要设置 步骤2.使用OpenXml 打开Excel 文件 步骤3.点击ReflectCode 功能,生成相应的代码文档 using ...