概念: 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的更多相关文章

  1. linux下的进程通信之管道与FIFO

    概念:管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条.管道的一端连接一个进程的输出.这个进程会向管道中放入信息.管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息. 优点:不需 ...

  2. Linux下多任务间通信和同步-概述

    Linux下多任务间通信和同步-概述 嵌入式开发交流群280352802,欢迎加入! 在前面,我们学习了两种多任务的实现手段:进程和线程.由于进程是工作在独立的内存空间中,不同的进程间不能直接访问到对 ...

  3. 操作系统-进程通信(信号量、匿名管道、命名管道、Socket)

    进程通信(信号量.匿名管道.命名管道.Socket) 具体的概念就没必要说了,参考以下链接. 信号量 匿名管道 命名管道 Socket Source Code: 1. 信号量(生产者消费者问题) #i ...

  4. Linux下的进程控制块(PCB)

    本文转载自Linux下的进程控制块(PCB) 导语 进程在操作系统中都有一个户口,用于表示这个进程.这个户口操作系统被称为PCB(进程控制块),在linux中具体实现是 task_struct数据结构 ...

  5. Linux下多任务间通信和同步-信号

    Linux下多任务间通信和同步-信号 嵌入式开发交流群280352802,欢迎加入! 1.概述 信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式.信号可以直接进行用户空间进程和内核进程之间的 ...

  6. linux下监控进程需掌握的四个命令

    linux下监控进程需掌握的四个命令   在LInux系统下,最困难的工作之一就是跟踪正在系统中运行的程序,尤其是现在,图形桌面使用很多的程序,只是为了生成一个桌面环境,系统中运行了太多的进程,幸运的 ...

  7. Linux下的进程与线程(二)—— 信号

    Linux进程之间的通信: 本文主要讨论信号问题. 在Linux下的进程与线程(一)中提到,调度器可以用中断的方式调度进程. 然而,进程是怎么知道自己需要被调度了呢?是内核通过向进程发送信号,进程才得 ...

  8. Linux下多任务间通信和同步-mmap共享内存

    Linux下多任务间通信和同步-mmap共享内存 嵌入式开发交流群280352802,欢迎加入! 1.简介 共享内存可以说是最有用的进程间通信方式.两个不用的进程共享内存的意思是:同一块物理内存被映射 ...

  9. Linux下java进程CPU占用率高分析方法

    Linux下java进程CPU占用率高分析方法 在工作当中,肯定会遇到由代码所导致的高CPU耗用以及内存溢出的情况.这种情况发生时,我们怎么去找出原因并解决. 一般解决方法是通过top命令找出消耗资源 ...

随机推荐

  1. 牛客练习赛33 E. tokitsukaze and Similar String (字符串哈希)

    题目链接:https://ac.nowcoder.com/acm/contest/308/E 题意:中文题 见链接 题解:哈希预处理(三哈希模板) #include <bits/stdc++.h ...

  2. 05_Tutorial 5: Relationships & Hyperlinked APIs 关系和超链接

    1.关系和超链接 0.文档 https://www.django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis/ h ...

  3. hadoop各版本下载地址

    http://mirror.bit.edu.cn/apache/hadoop/common/

  4. [Dart] Understand Classes and Inheritance in Dart

    We will look at how we can create classes and explore some various features. Dart adopts a single-in ...

  5. sql server 计算属性,计算字段的用法与解析

    SQL学习之计算字段的用法与解析   一.计算字段 1.存储在数据库表中的数据一般不是应用程序所需要的格式.大多数情况下,数据表中的数据都需要进行二次处理.下面举几个例子. (1).我们需要一个字段同 ...

  6. 关于 requestAnimationFrame 小结

    一.小谈 requestAnimationFrame: 说起 requestAnimationFrame,我们先看幅图: 相当一部分的浏览器的显示频率是16.7ms, 就是上图第一行的节奏,表现就是“ ...

  7. 初识QuartusII 9.0(破解,半加器的仿真,综合:上)

    由于在意大利期间,用的xilinx公司的ZYBO板子,相应的软件用ISE,SDK.回国买了altera公司的板子,自然也要学习国内较流行的软件(TB大西瓜家,因此相关例程也是大部分引用他家).Quar ...

  8. Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)

    3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当前 ...

  9. 在默认使用apache中央仓库时, 报错 protocol_version

    https://cloud.tencent.com/developer/ask/136221/answer/241408 2018年6月,为了提高安全性和符合现代标准,不安全的TLS 1.0和1.1协 ...

  10. hbuilder mui html vue ul li 自定义循环赋值ID

    <ul class="mui-table-view mui-table-view-chevron"> <li class="mui-table-view ...