linux进程间通信-信号量(semaphore)
一 为什么要使用信号量
二 信号量的工作原理
三 Linux的信号量机制
四 信号号相关的两个结构体
内核为每个信号量集合设置了一个semid_ds结构
struct semid_ds { struct ipc_permsem_perm ; structsem* sem_base ; //信号数组指针 ushort sem_nsem ; //此集中信号个数 time_t sem_otime ; //最后一次semop时间 time_t sem_ctime ; //最后一次创建时间} ;struct { ushort_t semval ; //信号量的值 short sempid ; //最后一个调用semop的进程ID ushort semncnt ; //等待该信号量值大于当前值的进程数(一有进程释放资源 就被唤醒) ushort semzcnt ; //等待该信号量值等于0的进程数} ;三 信号量的使用
#include <sys/sem.h>int semget (key_t key, int nsem, int oflag) ;#include <sys/sem.h>int semop (int semid, struct sembuf * opsptr, size_t nops) ;参数opsptr是一个指针,它指向一个信号量操作数组,信号量操作由sembuf结构表示:
struct sembuf{ short sem_num; // 除非使用一组信号量,否则它为0 short sem_op; // 信号量在一次操作中需要改变的数据,通常是两个数, // 一个是-1,即P(等待)操作,一个是+1,即V(发送信号)操作 short sem_flg; // 通常为SEM_UNDO,使操作系统跟踪信号,并在进程没有释放该信号量而终止时, // 操作系统释放信号量 };#include <sys/sem.h>int semctl (int semid, int semnum, int cmd, /*可选参数*/ ) ;四 信号量值的初始化
semget并不初始化各个信号量的值,这个初始化必须通过以SETVAL命令(设置集合中的一个值)或SETALL命令(设置集合中的所有值) 调用semctl来完成。
SystemV信号量的设计中,创建一个信号量集并将它初始化需两次函数调用是一个致命的缺陷。一个不完备的解决方案是:在调用semget时指定IPC_CREAT | IPC_EXCL标志,这样只有一个进程(首先调用semget的那个进程)创建所需信号量,该进程随后初始化该信号量。
五 例子
#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进程间通信--信号量
信号量绝对不同于信号,一定要分清,关于信号,上一篇博客中已经说过,如有疑问,请移驾! 信号量 一.是什么 信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件 ...
- Linux进程间通信—信号量
二.信号量(semophore) 信号量是一种计数器,可以控制进程间多个线程或者多个进程对资源的同步访问,它常实现为一种锁机制.实质上,信号量是一个被保护的变量,并且只能通过初始化和两个标准的原子操作 ...
- Linux - 进程间通信 - 信号量
一.概念 简单来讲,信号量是一个用来描述临界资源的资源个数的计数器. 信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件.外部设备等)来实现进程间通信, 他本身 ...
- Linux进程间通信(二):信号集函数 sigemptyset()、sigprocmask()、sigpending()、sigsuspend()
我们已经知道,我们可以通过信号来终止进程,也可以通过信号来在进程间进行通信,程序也可以通过指定信号的关联处理函数来改变信号的默认处理方式,也可以屏蔽某些信号,使其不能传递给进程.那么我们应该如何设定我 ...
- Linux进程间通信(五):信号量 semget()、semop()、semctl()
这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信 -- 信号.下面 ...
- 【转载】Linux的进程间通信-信号量
原文:Linux的进程间通信-信号量 Linux的进程间通信-信号量 版权声明: 本文章内容在非商业使用前提下可无需授权任意转载.发布. 转载.发布请务必注明作者和其微博.微信公众号地址,以便读者询问 ...
- Linux进程间通信——使用信号量
这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信——使用信号.下面 ...
- c/c++ linux 进程间通信系列5,使用信号量
linux 进程间通信系列5,使用信号量 信号量的工作原理: 由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的: P(sv):如果sv的值大于零,就给它减1:如果 ...
- Linux进程间通信--使用信号量【转】
本文转载自:http://blog.csdn.net/ljianhui/article/details/10243617 这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号 ...
随机推荐
- PowerDesigner
.PowerDesigner使用MySQL的auto_increment ◇问题描述: PD怎样能使主键id使用MySQL的auto_increment呢? ◇解决方法: 打开table p ...
- 【FFmpeg】Windows下FFmpeg编译
由于FFmpeg是基于Linux开发的开源项目,源代码和Windows下最常见的Visual Studio提供的C/C++编译器不兼容,因此它不能使用MSVC++编译,需要在Windows下配置一个类 ...
- 在selenium2.0中使用selenium1.0的API
Selenium2.0中使用WeDriver API对页面进行操作,它最大的优点是不需要安装一个selenium server就可以运行,但是对页面进行操作不如selenium1.0的Selenium ...
- [Cordova] Plugin开发入门
[Cordova] Plugin开发入门 Overview Cordova的设计概念,是在APP上透过Web控件来呈现Web页面,让Web开发人员可以操作熟悉的语言.工具来开发APP.使用Web页面来 ...
- Sublime text 3 快捷键的使用
快捷键的便捷使用: ctr+shift+n:打开新的sublime text ctr+shift+w:关闭sublime text ctr+o:打开 某个文件 ctrl+n:新建一个文本 ctrl+w ...
- sizzle源码分析 (3)sizzle 不能快速匹配时 选择器流程
如果快速匹配不成功,则会进入sizzle自己的解析顺序,主要流程如下: 总结流程如下: (1)函数sizzle是sizzle的入口,如果能querySelectAll快速匹配,则返回结果 (2)函数S ...
- jquery实现内容滚动
HTML代码: <div class="scollNews"> <ul> <li><a href="#">1&l ...
- ORA-03113解决方法
场景: 碰到ORA-00257归档日志写满的解决方法这篇日志当中描述的归档日志写满的情况. 此时我想将数据库切换到非归档模式,参考如何启动或关闭oracle的归档(ARCHIVELOG)模式进行操作, ...
- iOS中sqlite版本号
https://github.com/yapstudios/YapDatabase/wiki/SQLite-version-(bundled-with-OS) https://github.com/y ...
- spring.net (2)环境搭建 对(1)例子的解释和扩充
在上文中的例子实现了spring.net 控制反转的简单例子: 但是不免其中会有一些疑问. 例子中的配置文件是什么意思: app.config的配置规则可以参考web.config的配置详情 < ...