Linux进程间通信-信号量(semaphore)
作者:网络转载 发布时间:[ 2015/8/19 13:42:33 ] 推荐标签:测试开发技术 操作系统
3、信号量是操作
semctl函数对一个信号量执行各种控制操作。
#include <sys/sem.h>
int semctl (int semid, int semnum, int cmd, /*可选参数*/ ) ;
第四个参数是可选的,取决于第三个参数cmd。
参数semnum指定信号集中的哪个信号(操作对象)
参数cmd指定以下10种命令中的一种,在semid指定的信号量集合上执行此命令。
IPC_STAT 读取一个信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
IPC_SET 设置信号量集的数据结构semid_ds中的元素ipc_perm,其值取自semun中的buf参数。
IPC_RMID 将信号量集从内存中删除。
GETALL 用于读取信号量集中的所有信号量的值。
GETNCNT 返回正在等待资源的进程数目。
GETPID 返回后一个执行semop操作的进程的PID。
GETVAL 返回信号量集中的一个单个的信号量的值。
GETZCNT 返回这在等待完全空闲的资源的进程数目。
SETALL 设置信号量集中的所有的信号量的值。
SETVAL 设置信号量集中的一个单独的信号量的值。
六 信号量值的初始化
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 = 0;
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 = 0;
/* 创建信号量 */
sem_id = semget((key_t)1234, 1, 0666 | IPC_CREAT);
if(argc > 1)
{
/* 程序第一次被调用,初始化信号量 */
if(!set_semvalue())
{
fprintf(stderr, "Failed to initialize semaphore ");
exit(EXIT_FAILURE);
}
/* 设置要输出到屏幕中的信息,即其参数的第一个字符 */
message = argv[1][0];
sleep(2);
}
for(i = 0; i < 10; ++i)
{
/* 进入临界区 */
if(!semaphore_p())
{
exit(EXIT_FAILURE);
}
/* 向屏幕中输出数据 */
printf("%c", message);
/* 清理缓冲区,然后休眠随机时间 */
fflush(stdout);
sleep(rand() % 3);
/* 离开临界区前再一次向屏幕输出数据 */
printf("%c", message);
fflush(stdout);
/* 离开临界区,休眠随机时间后继续循环 */
if(!semaphore_v())
{
exit(EXIT_FAILURE);
}
sleep(rand() % 2);
}
sleep(10);
printf(" %d - finished ", getpid());
if(argc > 1)
{
/* 如果程序是第一次被调用,则在退出前删除信号量 */
sleep(3);
del_semvalue();
}
exit(EXIT_SUCCESS);
}
static int set_semvalue()
{
/* 用于初始化信号量,在使用信号量前必须这样做 */
union semun sem_union;
sem_union.val = 1;
if(semctl(sem_id, 0, SETVAL, sem_union) == -1)
{
return 0;
}
return 1;
}
static void del_semvalue()
{
/* 删除信号量 */
union semun sem_union;
if(semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
{
fprintf(stderr, "Failed to delete semaphore ");
}
}
static int semaphore_p()
{
/* 对信号量做减1操作,即等待P(sv)*/
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;//P()
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_p failed ");
return 0;
}
return 1;
}
static int semaphore_v()
{
/* 这是一个释放操作,它使信号量变为可用,即发送信号V(sv)*/
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;//V()
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id, &sem_b, 1) == -1)
{
fprintf(stderr, "semaphore_v failed ");
return 0;
}
return 1;
}
八 信号量集合的例子
#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 < 0)
{
/* Create process Error! */
fprintf(stderr,"Create Process Error!:%s ",strerror(errno));
exit(1) ;
}
if(pid > 0)
{
/* in parent process !*/
key = ftok(FILE_NAME,'a') ;
if(key == -1)
{
/* in parent process*/
fprintf(stderr,"Error in ftok:%s! ",strerror(errno));
exit(1) ;
}
semid = semget(key,MAX_SEMAPHORE,IPC_CREAT|0666); //创建信号量集合
if(semid == -1)
{
fprintf(stderr,"Error in semget:%s ",strerror(errno));
exit(1) ;
}
printf("Semaphore have been initialed successfully in parent process,ID is :%d ",semid);
sleep(2) ;
printf("parent wake up.... ");
/* 父进程在子进程得到semaphore的时候请求semaphore,此时父进程将阻塞直至子进程释放掉semaphore*/
/* 此时父进程的阻塞是因为semaphore 1 不能申请,因而导致的进程阻塞*/
for(i=0;i<MAX_SEMAPHORE;++i)
{
sb[i].sem_num = i ;
sb[i].sem_op = -1 ; /*表示申请semaphore*/
sb[i].sem_flg = 0 ;
}
printf("parent is asking for resource... ");
ret = semop(semid , sb ,10); //p()
if(ret == 0)
{
printf("parent got the resource! ");
}
/* 父进程等待子进程退出 */
waitpid(pid,NULL,0);
printf("parent exiting .. ");
exit(0) ;
}
else
{
/* in child process! */
key = ftok(FILE_NAME,'a') ;
if(key == -1)
{
/* in child process*/
fprintf(stderr,"Error in ftok:%s! ",strerror(errno));
exit(1) ;
}
semid = semget(key,MAX_SEMAPHORE,IPC_CREAT|0666);
if(semid == -1)
{
fprintf(stderr,"Error in semget:%s ",strerror(errno));
exit(1) ;
}
printf("Semaphore have been initialed successfully in child process,ID is:%d ",semid);
for(i=0;i<MAX_SEMAPHORE;++i)
{
/* Initial semaphore */
buf[i] = i + 1;
}
arg.array = buf;
ret = semctl(semid , 0, SETALL,arg);
if(ret == -1)
{
fprintf(stderr,"Error in semctl in child:%s! ",strerror(errno));
exit(1) ;
}
printf("In child , Semaphore Initailed! ");
/* 子进程在初始化了semaphore之后,申请获得semaphore*/
for(i=0;i<MAX_SEMAPHORE;++i)
{
sb[i].sem_num = i ;
sb[i].sem_op = -1 ;
sb[i].sem_flg = 0 ;
}
ret = semop(semid , sb , 10);//信号量0被阻塞
if( ret == -1 )
{
fprintf(stderr,"子进程申请semaphore失败:%s ",strerror(errno));
exit(1) ;
}
printf("child got semaphore,and start to sleep 3 seconds! ");
sleep(3) ;
printf("child wake up . ");
for(i=0;i < MAX_SEMAPHORE;++i)
{
sb[i].sem_num = i ;
sb[i].sem_op = +1 ;
sb[i].sem_flg = 0 ;
}
printf("child start to release the resource... ");
ret = semop(semid, sb ,10) ;
if(ret == -1)
{
fprintf(stderr,"子进程释放semaphore失败:%s ",strerror(errno));
exit(1) ;
}
ret = semctl(semid ,0 ,IPC_RMID);
if(ret == -1)
{
fprintf(stderr,"semaphore删除失败:%s! ",strerror(errno));
exit(1) ;
}
printf("child exiting successfully! ");
exit(0) ;
}
return 0;
}
【信号量的意图在于进程间同步,互斥锁和条件变量的意图则在于线程间同步。但是信号量也可用于线程间,互斥锁和条件变量也可用于进程间。我们应该使用适合具体应用的那组原语。】
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
Linux下开源的DDR压力测试工具曝Linux恶意软件:让树莓派设备挖掘数字货币linux系统中不同颜色的文件夹及根目录介绍软件测试工程师必知必会Linux命令Linux下DNS服务器配置如何成为不可替代的Linux运维工程师?详解Linux进程(作业)的查看和杀死Linux 日志定时轮询流程详解比特币勒索病毒不只Windows系统有,Linux版的来了Linux日志定时轮询流程详解Linux iommu和vfio概念空间解构Linux系统如何低于TCP洪水攻击Linux无损调整分区大小Linux下防火墙配置实例Linux使用Jexus托管Asp.Net Core应用程序Linux中引号的那些事
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11热门文章
常见的移动App Bug??崩溃的测试用例设计如何用Jmeter做压力测试QC使用说明APP压力测试入门教程移动app测试中的主要问题jenkins+testng+ant+webdriver持续集成测试使用JMeter进行HTTP负载测试Selenium 2.0 WebDriver 使用指南