Linux互斥和同步应用程序(四):posix互斥信号和同步
当信号量的值为1时。能够实现相互排斥的功能。此时信号量就是二值信号量,假设信号量的值大于一时。能够实现进程(线程)并发运行。
信号量和相互排斥锁条件变量之间的差别是:相互排斥锁必须由给它上锁的进程(线程)来解锁,而信号灯P操作不必由运行过它V操作的进程(线程)来运行;相互排斥锁类似于二值信号量。要么加锁。要么解锁;当向条件变量发信号时,假设此时没有等待在该条件变量上的线程。信号将丢失。而信号量不会。信号量主要用于之间同步。但也能够用在线程之间。
相互排斥锁和条件变量主要用于线程同步,但也能够用于进程间的同步。
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#include <semaphore.h> sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);
Link with -pthread
#include <semaphore.h>
int sem_close(sem_t *sem);
Link with -pthread.
#include <semaphore.h>
int sem_unlink(const char *name);
Link with -pthread.
#include <semaphore.h>
int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
Link with -pthread.
函数原型:
#include <semaphore.h>
int sem_post(sem_t *sem);
Link with -pthread.
#include <semaphore.h>
int sem_getvalue(sem_t *sem, int *sval);
Link with -pthread.
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
Link with -pthread.
首先我们来看看使用信号量实现对共享内存段的相互排斥訪问。
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
......
pthread_mutex_lock(&mutex);//加锁
......
/*share memory handle*/
......
pthread_mutex_unlock(&mutex);//解锁
......如今我们也使用类似方式来实现:sem_t *sem_mutex = NULL;
......
SLN_MUTEX_SHM_LOCK(SEM_MUTEX_FILE, sem_mutex);//加锁
......
/*share memory handle*/
......
SLN_MUTEX_SHM_UNLOCK(sem_mutex);//解锁
......当中SEM_MUTEX_FILE为sem_open函数须要的有名信号量名称。
当中两个加锁解锁的实现为:#define SLN_MUTEX_SHM_LOCK(shmfile, sem_mutex) do {\
sem_mutex = sem_open(shmfile, O_RDWR | O_CREAT, 0666, 1);\
if (SEM_FAILED == sem_mutex) {\
printf("sem_open(%d): %s\n", __LINE__, strerror(errno));\
}\
sem_wait(sem_mutex);\
}while(0) #define SLN_MUTEX_SHM_UNLOCK(sem_mutex) do {sem_post(sem_mutex);} while(0)事实上就是初始化一个二值信号量,其初始值为1。并运行wait操作,使信号量的值变为0,此时其他进程想要操作共享内存时也须要运行wait操作,但此时信号量的值为0,所以開始等待信号量的值变为1。当当前进程操作完共享内存后,開始解锁,运行post操作将信号量的值加一,此时其他进程的wait能够返回了。以下为一个相互排斥訪问共享内存的演示样例。posix共享内存实现请查看前面IPC的系列文章。ser process:int nms_shm_get(char *shm_file, void **shm, int mem_len)
{
int fd; fd = shm_open(shm_file, O_RDWR | O_CREAT, 0666);
if (fd < 0) {
printf("shm_pen <%s> failed: %s\n", shm_file, strerror(errno));
return -1;
} ftruncate(fd, mem_len); *shm = mmap(NULL, mem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (MAP_FAILED == *shm) {
printf("mmap: %s\n", strerror(errno));
return -1;
} return 0;
}
int main(int argc, const char *argv[])
{
sem_t *sem_mutex = NULL;
char *str = NULL; SLN_MUTEX_SHM_LOCK(SEM_MUTEX_FILE, sem_mutex); //加锁 nms_shm_get(SHM_FILE, (void **)&str, SHM_MAX_LEN); //以下三行相互排斥訪问共享内存
sleep(6);
snprintf(str, SHM_MAX_LEN, "posix semphore server!"); SLN_MUTEX_SHM_UNLOCK(sem_mutex); //解锁 sleep(6); shm_unlink(SHM_FILE); return 0;
}client process:int main(int argc, const char *argv[])
{
sem_t *sem_mutex;
char *str = NULL;
SLN_MUTEX_SHM_LOCK(SEM_MUTEX_FILE, sem_mutex);
nms_shm_get(SHM_FILE, (void **)&str, SHM_MAX_LEN);
printf("client get: %s\n", str);
SLN_MUTEX_SHM_UNLOCK(sem_mutex);
return 0;
}先启动服务进程首先加锁,创建共享内存并操作它。加锁中sleep 6秒,以便測试客户进程是否在服务进程未释放锁时处于等待状态。客户进程在服务进程启动之后立即启动,此时处于等待状态,当服务进程6秒之后解锁,客户进程获得共享内存信息。再过6秒之后,服务进程删除共享内存,客户进程再此获取共享内存失败。# ./server &
[1] 21690
# ./client
client get: posix semphore server!
# ./client
shm_open <share_memory_file> failed: No such file or directory
client get: (null)
[1]+ Done ./serverposix有名信号量创建的信号量文件和共享内存文件在/dev/shm/文件夹下:# ls /dev/shm/
sem.sem_mutex share_memory_file
#在两个进程共享数据时,当一个进程向共享内存写入了数据后须要通知另外的进程,这就须要两个进程之间实现同步,这里我们给上面的程序在相互排斥的基础上加上同步操作。同步也是使用posix信号量来实现。server process:int main(int argc, const char *argv[])
{
sem_t *sem_mutex = NULL;
sem_t *sem_consumer = NULL, *sem_productor = NULL;
int semval;
char *sharememory = NULL; sem_consumer = sem_open(SEM_CONSUMER_FILE, O_CREAT, 0666, 0); //初始化信号量sem_consumer 。并设置初始值为0
if (SEM_FAILED == sem_consumer) {
printf("sem_open <%s>: %s\n", SEM_CONSUMER_FILE, strerror(errno));
return -1;
} sem_productor = sem_open(SEM_PRODUCTOR_FILE, O_CREAT, 0666, 0);//初始化信号量sem_productor ,并设置初始值为0
if (SEM_FAILED == sem_productor) {
printf("sem_open <%s>: %s\n", SEM_PRODUCTOR_FILE, strerror(errno));
return -1;
} for (;;) {//服务进程一直循环处理客户进程请求
sem_getvalue(sem_consumer, &semval);
printf("%d waiting...\n", semval);
if (sem_wait(sem_consumer) < 0) {//假设sem_consumer为0,则堵塞在此,等待客户进程post操作使sem_consumer大于0。此处和客户进程同步
printf("sem_wait: %s\n", strerror(errno));
return -1;
}
printf("Get request...\n"); SLN_MUTEX_SHM_LOCK(SEM_MUTEX, sem_mutex);//此处開始相互排斥訪问共享内存
nms_shm_get(SHM_FILE, (void **)&sharememory, SHM_MAX_LEN);
sleep(6);
snprintf(sharememory, SHM_MAX_LEN, "Hello, this is server's message!");
SLN_MUTEX_SHM_UNLOCK(sem_mutex); sem_post(sem_productor);//使信号量sem_productor加一,使堵塞的客户进程继续运行
printf("Response request...\n");
} sem_close(sem_consumer);
sem_close(sem_productor);
return 0;
}client process:
int main(int argc, const char *argv[])
{
sem_t *sem_consumer = NULL, *sem_productor = NULL;
struct timespec timeout;
int ret;
char *sharememory = NULL;
sem_t *sem_mutex;
sem_consumer = sem_open(SEM_CONSUMER_FILE, O_RDWR);//获取信号量sem_consumer的值
if (SEM_FAILED == sem_consumer) {
printf("sem_open <%s>: %s\n", SEM_CONSUMER_FILE, strerror(errno));
return -1;
}
sem_productor = sem_open(SEM_PRODUCTOR_FILE, O_RDWR);//获取信号量sem_productor 的值
if (SEM_FAILED == sem_productor) {
printf("sem_open <%s>: %s\n", SEM_PRODUCTOR_FILE, strerror(errno));
return -1;
}
//clear_exist_sem(sem_productor); SLN_MUTEX_SHM_LOCK(SEM_MUTEX, sem_mutex);//相互排斥訪问共享内存
nms_shm_get(SHM_FILE, (void **)&sharememory, SHM_MAX_LEN);
printf("sharememory: %s\n", sharememory);
SLN_MUTEX_SHM_UNLOCK(sem_mutex); sem_post(sem_consumer);//信号量sem_consumer加一。唤醒是堵塞在该信号量上的服务进程
printf("Post...\n");
sem_wait(sem_productor);//等待服务进程回应
/*
timeout.tv_sec = time(NULL) + SEM_TIMEOUT_SEC;
timeout.tv_nsec = 0;
ret = sem_timedwait(sem_productor, &timeout);
if (ret < 0) {
printf("sem_timedwait: %s\n", strerror(errno));
}
*/ printf("Get response...\n");
sem_close(sem_consumer);
sem_close(sem_productor); return 0;
}本节演示样例源代码下载:
版权声明:本文博主原创文章。博客,未经同意不得转载。假设你认为你的实际物品,请点击以下“最佳”。
Linux互斥和同步应用程序(四):posix互斥信号和同步的更多相关文章
- 线程同步 - POSIX互斥锁
线程同步 - POSIX互斥锁 概括 本文讲解POSIX中互斥量的基本用法,从而能达到简单的线程同步.互斥量是一种特殊的变量,它有两种状态:锁定以及解锁.如果互斥量是锁定的,就有一个特定的线程持有或者 ...
- java同步和互斥【用具体程序说明】
java同步和互斥[用具体程序说明] 所有对象都自动含有单一的锁,也就是所有对象都有且只有唯一的锁,所以当某个任务(线程)访问一个类A中含有sycnhronized的方法是,那么 ...
- linux设备驱动归纳总结(四):5.多处理器下的竞态和并发【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-67673.html linux设备驱动归纳总结(四):5.多处理器下的竞态和并发 xxxxxxxxxx ...
- 【Linux开发】linux设备驱动归纳总结(四):5.多处理器下的竞态和并发
linux设备驱动归纳总结(四):5.多处理器下的竞态和并发 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
- linux设备驱动归纳总结(四):4.单处理器下的竞态和并发【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-67005.html linux设备驱动归纳总结(四):4.单处理器下的竞态和并发 xxxxxxxxxx ...
- linux设备驱动归纳总结(四):3.抢占和上下文切换【转】
本文转载自:http://blog.chinaunix.net/uid-25014876-id-65711.html linux设备驱动归纳总结(四):3.抢占和上下文切换 xxxxxxxxxxxxx ...
- [一个经典的多线程同步问题]解决方案三:互斥量Mutex
本篇通过互斥量来解决线程的同步,学习其中的一些知识. 互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行为非常相似,并且互斥量可以用于不同进程中的线程互斥访问资源.使用互 ...
- ReactiveSwift源码解析(十一) Atomic的代码实现以及其中的Defer延迟、Posix互斥锁、递归锁
本篇博客我们来聊一下ReactiveSwift中的原子性操作,在此内容上我们简单的聊一下Posix互斥锁以及递归锁的概念以及使用场景.然后再聊一下Atomic的代码实现.Atomic主要负责多线程下的 ...
- linux 异步信号的同步处理方式
关于代码的可重入性,设计开发人员一般只考虑到线程安全,异步信号处理函数的安全却往往被忽略.本文首先介绍如何编写安全的异步信号处理函数:然后举例说明在多线程应用中如何构建模型让异步信号在指定的线程中以同 ...
随机推荐
- poj 1198 hdu 1401 搜索+剪枝 Solitaire
写到一半才发现能够用双向搜索4层来写,但已经不愿意改了,干脆暴搜+剪枝水过去算了. 想到一个非常水的剪枝,h函数为 当前点到终点4个点的最短距离加起来除以2.由于最多一步走2格,然后在HDU上T了, ...
- hdu4553(线段树)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4553 线段树功能:update:区间替换 query:询问满足条件的最左断点 分析:poj3667的加 ...
- 写代码质量改善java计划151建议——导航开始
2014-05-16 09:08 by Jeff Li 前言 系列文章:[传送门] 下个星期度过这几天的奋战,会抓紧java的进阶学习.听过一句话,大哥说过,你一个月前的代码去看下,慘不忍睹是吧.确实 ...
- Android:主题(Theme)
1.主题和样式的区别主要区别在 主题不能作用于单个View组建,主题应该对整个应用中的所有Activity起作用或者对指定的Activity起作用. 主题定义的格式应该是改变窗口的外观格式,例如窗口变 ...
- poj 2010 Moo University - Financial Aid (贪心+线段树)
转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove 骗一下访问量.... 题意大概是:从c个中选出n个 ...
- Linux渗透+SSH内网转发
http://www.jb51.net/hack/58514.html http://blog.chinaunix.net/uid-756931-id-353243.html http://blog. ...
- hdu4635(最多加多少边,使得有向图不是强连通图)
连边的最后肯定是两个集合x,yx集合的每个元素,到y集合中的每个元素都是单向的边x集合,和y集合都是完全图设a为x集合的点的个数, b为y集合的那么答案就是 a * b + a*(a-1) + b*( ...
- python学习笔记之九:模块和包
Python的标准安装包括一组模块,称为标准库.这里介绍模块的工作方式,学习如何使用它们. 一. 模块 1.1 用import从外部模块获取函数并为自己的程序所用: >>> from ...
- cocos2dx的发展的例子2048(加入动画版)
网上找了很多写作教程2048.只是不知道卡的移动动画,我写了一个完美的动画版少. 开发步骤: 1,一个设计CardSprite类. 2,设计主游戏场景GameScene,实现游戏逻辑,加入动画逻辑. ...
- HP服务器更换主板前后的注意事项
问题 X86服务器免不了会出现故障,以我们实验室使用的HP服务器为例,已经有几台因为各种故障更换过主板了,更换主板前后有些事情需要我们应该注意或处理, 这里记录如下,其中第二.三点是针对我们所使用的C ...