linux下的进程通信之信号量semaphore
概念: IPC 信号量和内核信号量非常相似,是内核信号量的用户态版本。
优点:每个IPC信号量可以保护一个或者多个信号量值的集合,而不像内核信号量一样只有一个值,这意味着同一个IPC资源可以保护多个独立、共享的数据结构。另外,IPC信号量提供了一种失效安全机制,这是针对进程不能取消以前对信号量执行的操作就死亡的情况的。当进程使用这种机制时,由此引起的操作就是所谓的可取消的信号量操作。当进程死亡时,如果从来没有开始它的操作,那么它的所有IPC信号量都可以恢复成原来的值。这有助于防止其他使用相同信号量的进程无限地停留在阻塞状态,从而导致正在结束的进程不能手工取消它的信号量操作。
缺点:必须和受保护的资源搭配使用,常常和共享内存搭配使用。
基本原理:如果受保护的资源是可用的,那么信号量的值就是正数;如果受保护的资源现不能使用,那么信号量的值就是负数或0.要访问资源的进程试图把信号量的值减1,但是,内核阻塞这个进程,直到在这个信号量上的操作产生一个正值。当进程释放受保护的资源时,就把信号量的值增加1;在这样处理的过程中,其他所有正在等待这个信号量的进程都必须被唤醒。
代码示例:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/sem.h> union semun
{
int val;
struct semid_ds *buf;
unsigned short *arry;
}; static int sem_id = ; static int set_semvalue();
static void del_semvalue();
static int semaphore_p();
static int semaphore_v(); int main(int argc, char *argv[])
{
char message = 'X';
int i = ; /* 创建信号量 */
sem_id = semget((key_t), , | IPC_CREAT); if(argc > )
{
/* 程序第一次被调用,初始化信号量 */
if(!set_semvalue())
{
fprintf(stderr, "Failed to initialize semaphore\n");
exit(EXIT_FAILURE);
}
/* 设置要输出到屏幕中的信息,即其参数的第一个字符 */
message = argv[][];
sleep();
} for(i = ; i < ; ++i)
{
/* 进入临界区 */
if(!semaphore_p())
{
exit(EXIT_FAILURE);
}
/* 向屏幕中输出数据 */
printf("%c", message);
/* 清理缓冲区,然后休眠随机时间 */
fflush(stdout);
sleep(rand() % );
/* 离开临界区前再一次向屏幕输出数据 */
printf("%c", message);
fflush(stdout);
/* 离开临界区,休眠随机时间后继续循环 */
if(!semaphore_v())
{
exit(EXIT_FAILURE);
}
sleep(rand() % );
}
sleep();
printf("\n%d - finished\n", getpid()); if(argc > )
{
/* 如果程序是第一次被调用,则在退出前删除信号量 */
sleep();
del_semvalue();
}
exit(EXIT_SUCCESS);
} static int set_semvalue()
{
/* 用于初始化信号量,在使用信号量前必须这样做 */
union semun sem_union; sem_union.val = ;
if(semctl(sem_id, , SETVAL, sem_union) == -)
{
return ;
}
return ;
} static void del_semvalue()
{
/* 删除信号量 */
union semun sem_union; if(semctl(sem_id, , IPC_RMID, sem_union) == -)
{
fprintf(stderr, "Failed to delete semaphore\n");
}
} static int semaphore_p()
{
/* 对信号量做减1操作,即等待P(sv)*/
struct sembuf sem_b;
sem_b.sem_num = ;
sem_b.sem_op = -;//P()
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id, &sem_b, ) == -)
{
fprintf(stderr, "semaphore_p failed\n");
return ;
}
return ;
} static int semaphore_v()
{
/* 这是一个释放操作,它使信号量变为可用,即发送信号V(sv)*/
struct sembuf sem_b;
sem_b.sem_num = ;
sem_b.sem_op = ;//V()
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id, &sem_b, ) == -)
{
fprintf(stderr, "semaphore_v failed\n");
return ;
}
return ;
}
信号量集合的例子:
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#include<time.h>
#include<unistd.h>
#include<sys/wait.h>
#define MAX_SEMAPHORE 10
#define FILE_NAME "test2.c" union semun{
int val ;
struct semid_ds *buf ;
unsigned short *array ;
struct seminfo *_buf ;
}arg; struct semid_ds sembuf; int main()
{
key_t key ;
int semid ,ret,i;
unsigned short buf[MAX_SEMAPHORE] ;
struct sembuf sb[MAX_SEMAPHORE] ;
pid_t pid ; pid = fork() ;
if(pid < )
{
/* Create process Error! */
fprintf(stderr,"Create Process Error!:%s\n",strerror(errno));
exit() ;
} if(pid > )
{
/* in parent process !*/
key = ftok(FILE_NAME,'a') ;
if(key == -)
{
/* in parent process*/
fprintf(stderr,"Error in ftok:%s!\n",strerror(errno));
exit() ;
} semid = semget(key,MAX_SEMAPHORE,IPC_CREAT|); //创建信号量集合
if(semid == -)
{
fprintf(stderr,"Error in semget:%s\n",strerror(errno));
exit() ;
}
printf("Semaphore have been initialed successfully in parent process,ID is :%d\n",semid);
sleep() ;
printf("parent wake up....\n");
/* 父进程在子进程得到semaphore的时候请求semaphore,此时父进程将阻塞直至子进程释放掉semaphore*/
/* 此时父进程的阻塞是因为semaphore 1 不能申请,因而导致的进程阻塞*/
for(i=;i<MAX_SEMAPHORE;++i)
{
sb[i].sem_num = i ;
sb[i].sem_op = - ; /*表示申请semaphore*/
sb[i].sem_flg = ;
} printf("parent is asking for resource...\n");
ret = semop(semid , sb ,); //p()
if(ret == )
{
printf("parent got the resource!\n");
}
/* 父进程等待子进程退出 */
waitpid(pid,NULL,);
printf("parent exiting .. \n");
exit() ;
}
else
{
/* in child process! */
key = ftok(FILE_NAME,'a') ;
if(key == -)
{
/* in child process*/
fprintf(stderr,"Error in ftok:%s!\n",strerror(errno));
exit() ;
} semid = semget(key,MAX_SEMAPHORE,IPC_CREAT|);
if(semid == -)
{
fprintf(stderr,"Error in semget:%s\n",strerror(errno));
exit() ;
}
printf("Semaphore have been initialed successfully in child process,ID is:%d\n",semid); for(i=;i<MAX_SEMAPHORE;++i)
{
/* Initial semaphore */
buf[i] = i + ;
} arg.array = buf;
ret = semctl(semid , , SETALL,arg);
if(ret == -)
{
fprintf(stderr,"Error in semctl in child:%s!\n",strerror(errno));
exit() ;
}
printf("In child , Semaphore Initailed!\n"); /* 子进程在初始化了semaphore之后,就申请获得semaphore*/
for(i=;i<MAX_SEMAPHORE;++i)
{
sb[i].sem_num = i ;
sb[i].sem_op = - ;
sb[i].sem_flg = ;
} ret = semop(semid , sb , );//信号量0被阻塞
if( ret == - )
{
fprintf(stderr,"子进程申请semaphore失败:%s\n",strerror(errno));
exit() ;
} printf("child got semaphore,and start to sleep 3 seconds!\n");
sleep() ;
printf("child wake up .\n");
for(i=;i < MAX_SEMAPHORE;++i)
{
sb[i].sem_num = i ;
sb[i].sem_op = + ;
sb[i].sem_flg = ;
} printf("child start to release the resource...\n");
ret = semop(semid, sb ,) ;
if(ret == -)
{
fprintf(stderr,"子进程释放semaphore失败:%s\n",strerror(errno));
exit() ;
} ret = semctl(semid , ,IPC_RMID);
if(ret == -)
{
fprintf(stderr,"semaphore删除失败:%s!\n",strerror(errno));
exit() ;
} printf("child exiting successfully!\n");
exit() ;
}
return ;
}
linux下的进程通信之信号量semaphore的更多相关文章
- linux下的进程通信之管道与FIFO
概念:管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条.管道的一端连接一个进程的输出.这个进程会向管道中放入信息.管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息. 优点:不需 ...
- Linux下多任务间通信和同步-概述
Linux下多任务间通信和同步-概述 嵌入式开发交流群280352802,欢迎加入! 在前面,我们学习了两种多任务的实现手段:进程和线程.由于进程是工作在独立的内存空间中,不同的进程间不能直接访问到对 ...
- 操作系统-进程通信(信号量、匿名管道、命名管道、Socket)
进程通信(信号量.匿名管道.命名管道.Socket) 具体的概念就没必要说了,参考以下链接. 信号量 匿名管道 命名管道 Socket Source Code: 1. 信号量(生产者消费者问题) #i ...
- Linux下的进程控制块(PCB)
本文转载自Linux下的进程控制块(PCB) 导语 进程在操作系统中都有一个户口,用于表示这个进程.这个户口操作系统被称为PCB(进程控制块),在linux中具体实现是 task_struct数据结构 ...
- Linux下多任务间通信和同步-信号
Linux下多任务间通信和同步-信号 嵌入式开发交流群280352802,欢迎加入! 1.概述 信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式.信号可以直接进行用户空间进程和内核进程之间的 ...
- linux下监控进程需掌握的四个命令
linux下监控进程需掌握的四个命令 在LInux系统下,最困难的工作之一就是跟踪正在系统中运行的程序,尤其是现在,图形桌面使用很多的程序,只是为了生成一个桌面环境,系统中运行了太多的进程,幸运的 ...
- Linux下的进程与线程(二)—— 信号
Linux进程之间的通信: 本文主要讨论信号问题. 在Linux下的进程与线程(一)中提到,调度器可以用中断的方式调度进程. 然而,进程是怎么知道自己需要被调度了呢?是内核通过向进程发送信号,进程才得 ...
- Linux下多任务间通信和同步-mmap共享内存
Linux下多任务间通信和同步-mmap共享内存 嵌入式开发交流群280352802,欢迎加入! 1.简介 共享内存可以说是最有用的进程间通信方式.两个不用的进程共享内存的意思是:同一块物理内存被映射 ...
- Linux下java进程CPU占用率高分析方法
Linux下java进程CPU占用率高分析方法 在工作当中,肯定会遇到由代码所导致的高CPU耗用以及内存溢出的情况.这种情况发生时,我们怎么去找出原因并解决. 一般解决方法是通过top命令找出消耗资源 ...
随机推荐
- eclipse/myeclipse SVN资源库URL中文乱码问题解决办法
右击选择资源库地址 可以自定义名称
- Jquery检验输入值
1.检验邮件 function chkEmail(strEmail) { if (!/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w ...
- 百度UEditor编辑器从word粘贴公式
官网地址http://ueditor.baidu.com Git 地址 https://github.com/fex-team/ueditor 参考博客地址 http://blog.ncmem.com ...
- 【原创】go语言之打印目录
package main import ( "fmt" "io/ioutil" "log" ) func listFiles(dirname ...
- 提高python运行效率的方法
让关键代码依赖于外部包:你可以为紧急的任务使用C.C++或机器语言编写的外部包,这样可以提高应用程序的性能 使用生成器,因为可以节约大量内存 多个if elif条件判断,可以把最有可能先发生的条件放到 ...
- selenium鼠标操作
#-*- coding:utf-8 -*- import time from selenium import webdriver from selenium.webdriver.common.acti ...
- 微信小程序入门与实战 从0到1进行细致讲解 涵盖小程序开发核心技能下载
第1章 什么是微信小程序? 第2章 小程序环境搭建与开发工具介绍 第3章 从一个简单的“欢迎“页面开始小程序之旅 第4章 第二个页面:新闻阅读列表 第5章 小程序的模板化与模块化 第6章 构建新闻详情 ...
- (转)mysql更改数据目录
mysql 更改默认数据目录 http://www.cnblogs.com/chenny7/p/3642363.html 本文主要介绍在CentOS下通过yum命令安装MySQL之后,如何移动默认数据 ...
- lucene反向索引——倒排表无论是文档号及词频,还是位置信息,都是以跳跃表的结构存在的
转自:http://www.cnblogs.com/forfuture1978/archive/2010/02/02/1661436.html 4.2. 反向信息 反向信息是索引文件的核心,也即反向索 ...
- idea出现Error configuring application listener of class org.springframework.web.context.ContextLoader
在IDEA中写spring mvc时出现Error configuring application listener of class org.springframework.web.context. ...