【进程间通信】------信号量(sems)

2024-03-04 08:50

本文主要是介绍【进程间通信】------信号量(sems),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一直想看看ftok函数,今天就在这里进行简单的介绍下
ftok()函数我们在进行IPC通讯的时候必须指定一个ID值,这个值通常情况下就是由ftok进行提供。

ftok原型如下:
key_t ftok( char * fname, int id )
参数说明:
fname就时您指定的文档名
id是子序号。
返回值:
在一般的UNIX实现中,是将文档的索引节点号取出,前面加上子序号得到key_t的返回值。
如指定文档的索引节点号为65538,换算成16进制为0x010002,而您指定的ID值为38,换算成16进制 为 0x26,则最后的key_t返回值为0x26010002。

认识信号量

信号量主要用于同步和互斥的,信号量的本质是一个计数器,信号量记录了临界资源的数目,数目为多少,信号量的数目就为多少,信号量的值为1的称为二元信号量(也成二元信号量称为互斥锁)。信号量的生命周期随内核。

进程互斥

  • 由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关系为进程的互斥。
  • 系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源。
  • 在进程中涉及到互斥资源的程序叫做临界区
    进程同步指的是多个进程需要相互配合共同完成一项任务。
    信号量和P,V原语(p、v操作是原子的,要么做了,要么没做,无中间态产生。`

  • 信号量和P、V原语由Dijkstra(迪杰斯特拉)提出的

  • 信号量
    互斥:P、V在同一个进程中
    同步: P、V不在同一个进程当中
    信号量的含义:
    s>0:s表示的是可用资源的数目
    s=0:表示无可用资源,无等待进程
    s<0:|s|表示等待队列中的进程个数

信号量结构体伪代码

信号量本质上是一个计数器
struct   semaphore
{int  value;point_PCB  queue;
}

p原语

p(s)
{
s.value=s.value–;
if(s.value<0)
{
该进程状态置为等待状状态
该进程的PCB插入到相应的等待队列s.queue末尾
}
}

v原语

v(s)
{
s.value=s.value++;
if(s.value>=0)
{
唤醒相应等待队列s.queue中等待的一个进程
改变其状态为就绪态
并将其插入就绪队列
}
}

信号量集函数

semget函数

功能:用来创建和访问一个信号量集
原型:
int semget(key_t key,int nsems,int semflgs);
参数:
key:信号量集的名字
nsems:信号量集中信号量的个数
semflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的
返回值;成功返回一个非负整数,即该信号即的标识码,失败返回的是-1

shmctl函数

功能:用于控制信号量集
原型:
int semctl(int semid,int semnum,int cmd,….)
参数:
semid:由semget返回的信号集标识码
semnum:信号集中信号量的编号
cmd:将来采取的动作(有三个可能值)
最后一个参数根据命令的不同而不同
返回值:成功返回的是0,失败返回的是-1

命令说明
SETVAL设置信号量集中的信号量的计数值
GETVAL获取信号量集中的信号量的计数值
IPC_STAT把semid_ds结构中的数据设置为信号量集的当前关联值
IPC_SET在进程有足够权限前提下,把信号量集的当前关联值设置为semid_ds数据结构中的值
IPC_RMID删除信号集

semop函数

用来创建和访问一个信号量集
原型:
int semop(int semid ,struct sembuf *sops,unsigned nsops);
参数:
semid:是该信号量的标识码,也是semget函数的返回值
sops:是个指向一个结构数值的指针
nsops:信号量的个数
返回值:成功返回,失败返回-1

sembuf 结构体:

       struct sembuf{short sem_num;short sem_op;short sem_flag;};

sem_num是信号量的编号。
sem_op是信号量一次pv操作时加减的数值,一般只会用到两个值:
一个是“-1“,也就是进行的是p操作,等待信号量变为可用
一个是“+1”,也就是我们进行的v操作,发出信号量已经变得可用
sem_flag两个取值是IPC_NOWAIT或SEM_UNDO

实例代码:
两个进程同时进行打印,显示器为临界资源,使用二元信号量(互斥锁)进行保护。
代码实现:

Makefile

 sem:comm.c sem.c                                                                                                                                          2         gcc -o $@ $^3 .PHONY:clean4 clean: 5         rm -f sem6 

comm.h

 1 #include <stdio.h>2 #include <sys/types.h>3 #include <sys/ipc.h>4 #include <sys/sem.h>5 6 7 #define PATHNAME "."8 #define PROJ_ID 0x66669 10 union semun{11     int val;12     struct semid_ds *buf;13     unsigned short *arr;14     struct seminfo *_buf;15 };16 int cerateSemSet(int nums);17 int initSem (int semid,int nums,int initVal);18 int P(int semid,int who);19 int V(int semid,int who);20 int destroySemSet(int semid);21 22 23                                                                                                                                                           
~                       

comm.c

1 #include "comm.h"2 3 static int  commSemSet(int nums,int flags)4 {5     key_t _key=ftok(PATHNAME,PROJ_ID);6     if(_key<0){7         perror("ftork");8         return -1;9     }10     int semid=semget(_key,nums,flags);11     if(semid<0){12         perror("semget");13         return -2;14     }15     return semid;16 }17 int createSemSet(int nums){18     return commSemSet(nums,IPC_CREAT|IPC_EXCL|0666);19 }20 int getSemSet(int nums){21     return commSemSet(nums,IPC_CREAT);22 }23 24 int initSem(int semid,int nums,int initVal){25     union semun _un;26     _un.val=initVal;27     if(semctl(semid,nums,SETVAL,_un)<0){28         perror("semctl");29         return -1;30     }31     return 0;32 }33 34 static int commPV(int semid,int who,int op){35     struct sembuf _sf;36     _sf.sem_num=who;37     _sf.sem_op=op;38     _sf.sem_flg=0;39     if(semop(semid,&_sf,1)<0){40         perror("semop");41         return -1;42     }43     return 0;44 }45 46 int P(int semid,int who){47     return commPV(semid,who,1);48 }49 int V(int semid,int who){50    return commPV(semid,who,1);51 }52                                                                                                                                                                                                                                                                            53 int destroySemSet(int semid){54     if(semctl(semid,0,IPC_RMID)<0){55         perror("semctl");56         return -1;57     }58 }

sem.c

 1 #include "comm.h"2 3 int main()4 {5     int semid=createSemSet(1);6     initSem(semid,0,1);7     pid_t id=fork();8     if(id==0){9         int _semid=getSemSet(0);10         while(1){11             P(_semid,0);12             printf("A");13             fflush(stdout);14             usleep(100000);15             printf("A");16             fflush(stdout);17             usleep(100000);18             V(_semid,0);19         }20     }21     else {22         while(1){23             P(semid,0);24             printf("B");25             fflush(stdout);26             usleep(100000);27             printf("B");28             fflush(stdout);29             usleep(100000);30             V(semid,0);31         }32             wait(NULL);33         }34         destroySemSet(semid);35         return 0;36 }                                                                                                                                                                                                                                                                          

运行结果如下:
这里写图片描述
当我们再一次进行运行这个程序时,我们又会发现什么呢?
这里写图片描述
我们的解决的办法就是:
这里写图片描述

这篇关于【进程间通信】------信号量(sems)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/772655

相关文章

[Linux]:进程(下)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 1. 进程终止 1.1 进程退出的场景 进程退出只有以下三种情况: 代码运行完毕,结果正确。代码运行完毕,结果不正确。代码异常终止(进程崩溃)。 1.2 进程退出码 在编程中,我们通常认为main函数是代码的入口,但实际上它只是用户级

java 进程 返回值

实现 Callable 接口 与 Runnable 相比,Callable 可以有返回值,返回值通过 FutureTask 进行封装。 public class MyCallable implements Callable<Integer> {public Integer call() {return 123;}} public static void main(String[] args

C#关闭指定时间段的Excel进程的方法

private DateTime beforeTime;            //Excel启动之前时间          private DateTime afterTime;               //Excel启动之后时间          //举例          beforeTime = DateTime.Now;          Excel.Applicat

linux中使用rust语言在不同进程之间通信

第一种:使用mmap映射相同文件 fn main() {let pid = std::process::id();println!(

java线程深度解析(二)——线程互斥技术与线程间通信

http://blog.csdn.net/daybreak1209/article/details/51307679      在java多线程——线程同步问题中,对于多线程下程序启动时出现的线程安全问题的背景和初步解决方案已经有了详细的介绍。本文将再度深入解析对线程代码块和方法的同步控制和多线程间通信的实例。 一、再现多线程下安全问题 先看开启两条线程,分别按序打印字符串的

Golang进程权限调度包runtime

关于 runtime 包几个方法: Gosched:让当前线程让出 cpu 以让其它线程运行,它不会挂起当前线程,因此当前线程未来会继续执行GOMAXPROCS:设置最大的可同时使用的 CPU 核数Goexit:退出当前 goroutine(但是defer语句会照常执行)NumGoroutine:返回正在执行和排队的任务总数GOOS:目标操作系统NumCPU:返回当前系统的 CPU 核数量 p

如何保证android程序进程不到万不得已的情况下,不会被结束

最近,做一个调用系统自带相机的那么一个功能,遇到的坑,在此记录一下。 设备:红米note4 问题起因 因为自定义的相机,很难满足客户的所有需要,比如:自拍杆的支持,优化方面等等。这些方面自定义的相机都不比系统自带的好,因为有些系统都是商家定制的,难免会出现一个奇葩的问题。比如:你在这款手机上运行,无任何问题,然而你换一款手机后,问题就出现了。 比如:小米的红米系列,你启用系统自带拍照功能后

安卓玩机工具------小米工具箱扩展工具 小米机型功能拓展

小米工具箱扩展版                     小米工具箱扩展版 iO_Box_Mi_Ext是由@晨钟酱开发的一款适用于小米(MIUI)、多亲(2、2Pro)、多看(多看电纸书)的多功能工具箱。该工具所有功能均可以免root实现,使用前,请打开开发者选项中的“USB调试”  功能特点 【小米工具箱】 1:冻结MIUI全家桶,隐藏状态栏图标,修改下拉通知栏图块数量;冻结

flume系列之:记录一次flume agent进程被异常oom kill -9的原因定位

flume系列之:记录一次flume agent进程被异常oom kill -9的原因定位 一、背景二、定位问题三、解决方法 一、背景 flume系列之:定位flume没有关闭某个时间点生成的tmp文件的原因,并制定解决方案在博主上面这篇文章的基础上,在机器内存、cpu资源、flume agent资源都足够的情况下,flume agent又出现了tmp文件无法关闭的情况 二、

C++及AIDL服务间通信相关

只做细节展示,没有什么逻辑,陆续补充中