Linux15 --- 信号量、ipcs

article/2025/10/7 15:15:35

1、IPC机制:

进程间通信(管道、信号量、共享内存、消息队列、套接字)

2、信号量:

可以类比于红绿灯,对于路口这个共享的通行权,谁得到红绿灯的通行信号,才可以得到路口的通行权,没得到通信信号,就只能等待。

1)信号量的定义:

信号量是一个原子操作,例如+1、-1,不能被打断,只有等其操作完才能去使用。这里的+1 、 -1类比于资源的释放和获取,为二值信号量,只有两个值,其初始值为1,就只有0和1两个值。

定义:

信号量是一个特殊的变量,一般取正数值。它的值代表允许访问的资源数目, 获取资源时,需要对信号量的值进行原子减一,该操作被称为 P 操作。当信号量值为 0时,代表没有资源可用, P 操作会阻塞。释放资源时,需要对信号量的值进行原子加一,该操作被称为 V操作。信号量主要用来同步进程。 信号量的值如果只取 0,1,将其称为二值信号量。如果信号量的值大于 1,则称之为计数信号量。注意:正数值; 加一减一是一个原子操作;

2)临界资源和临界区的概念:

临界资源:计算机的软硬件资源,即同一时刻,只允许一个进程或者线程访问的资源;
临界区:访问临界资源的代码段;

2、信号量的一个例子

不加控制模拟使用打印机:
比如:进程 a 和进程 b 模拟访问打印机,进程 a 输出第一个字符‘ a’表示开始使用打印机,输出第二个字符‘ a’表示结束使用, b 进程操作与 a 进程相同。(由于打印机同
一时刻只能被一个进程使用,所以输出结果不应该出现 abab这样交替的结果)
在这里插入图片描述
代码示例:
a.c

//a.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
int main()
{int i=0;for(;i<5;i++){printf("A");fflush(stdout);int n=rand()%3;sleep(n);printf("A");fflush(stdout);n=rand()%3;sleep(n);}
}

b.c:

//b.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
int main()
{int i=0;for(;i<5;i++){printf("B");fflush(stdout);int n=rand()%3;sleep(n);printf("B");fflush(stdout);n=rand()%3;sleep(n);}
}

3、信号量的接口

(1)semget --创建或者获取一个已经存在的信号量

参数:

int semget(key_t key,int nsems,int semflg);

(key_t 其实为int类型,只不过)

key:给相同的key值,能得到相同的信号量。
nsems:创建几个信号量;
semflg:标志位,如果为创建:IPC_CREAT;
–如果为创建:为IPC_CREAT;
–如果为全新创建,也就是不知道是否有人创建过,则 IPC_CREATE | IPC_EXCL ,就是如果没有则创建,如果有则创建失败;

(2)semop --对信号量进改变,做p操作或者v操作;

p操作为获取资源;
v操作为释放资源;

参数:

int semop(int semid,struct sembuf *sops,unsigned nsops);

nsops :为结构体长度

semid:信号量的id号,也就是刚才semget的返回值;4;说明对哪个信号量进行操作;
sops:结构体指针,指向sembuf的结构体指针,

sembuf 结构体有三个成员变量:
sem_num 表示信号量的编号(即指定信号量集中的 信号量下标);
sem_op 表示是p还是v操作;1为v操作(加1),-1为p操作(减1);
sem_flg 为标志位;

(3)semct --对信号量进行控制;

参数:

int semctl(int semid,int semnum,int cmd,...);

semid:信号量id;
semnum:信号量编号;
cmd:命令:SETVAL:初始化信号量; IPC_RMID:删除信号量;

注意:联合体semun,这个联合体需要自己定义;
在这里插入图片描述
思路:
在这里插入图片描述

4、控制打印机的代码如下:

1)基础代码

a.c :

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>int main()
{int i = 0;for(;i < 5;i++){printf("A");fflush(stdout);int n = rand()%3;sleep(n);printf("A");fflush(stdout);n = rand()%3;sleep(n);}
}

b.c :

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>int main()
{int i = 0;for(;i < 5;i++){printf("B");fflush(stdout);int n = rand()%3;sleep(n);printf("B");fflush(stdout);n = rand()%3;sleep(n);}
}

同时运行(加&,后台运行):./a& ./b&
结果不一定完全相同,但都是成块出现,都是两个A两个B
在这里插入图片描述

2)思路

在这里插入图片描述
代码实现:

sem.h

//sem.h
#include <sys/sem.h>
#include <unistd.h>
#include <stdio.h>union semun
{int val;
};void sem_init();
void sem_p();
void sem_v();
void sem_destroy();

sem.c

//sem.c
#include "sem.h"static int semid=-1;//信号量的初始化实现
void sem_init()
{semid=semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);//1234为自己定义的if(semid==-1)//全新创建失败{semid=semget((key_t)1234,1,0600);//获取已经存在的信号量if(semid==-1)//获取再失败,是真的错了{perror("semget error");}}else//全新创建成功{//初始化union semun a;a.val=1;if(semctl(semid,0,SETVAL,a)==-1)//初始化,只有一个信号量,所以为0{perror("semctl init error");}}
}//p操作
void sem_p()
{struct sembuf buf;buf.sem_num=0;buf.sem_op=-1;//p操作buf.sem_flg=SEM_UNDO;//相当于操作系统记住你进行了p操作,如果异常结束,无法进行v操作,系统会帮你操作if(semop(semid,&buf,1)==-1)//出错处理{perror("p error");}
}//v操作
void sem_v()
{struct sembuf buf;buf.sem_num=0;buf.sem_op=1;//v操作buf.sem_flg=SEM_UNDO;//相当于操作系统记住你进行了p操作,如果异常结束,无法进行v操作,系统会帮你操作if(semop(semid,&buf,1)==-1)//出错{perror("v error");}
}//销毁操作
void sem_destroy()
{if(semctl(semid,0,IPC_RMID)==-1)//0表示占位{perror("destroy sem error");}
}

a.c

//a.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include "sem.h"
int main()
{int i=0;sem_init();for(;i<5;i++){//p v 操作之间为临界区,访问临界资源的代码段sem_p();printf("A");fflush(stdout);int n=rand()%3;sleep(n);printf("A");fflush(stdout);sem_v();n=rand()%3;sleep(n);//sem_v();可以放在此代码之后,但不好,效率过低}sleep(10);sem_destroy();//如果忘记销毁,或者程序出错,信号量可能还在,需要通过ipcs查看
}

b.c

//b.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include "sem.h"
int main()
{int i=0;sem_init();for(;i<5;i++){sem_p();printf("B");fflush(stdout);int n=rand()%3;sleep(n);printf("B");fflush(stdout);sem_v();n=rand()%3;sleep(n);}
}

5、三个进程分别输出"A"、“B”、“C”,要求输出结果必须是"AABBCCAABB…"

思路如下:
在这里插入图片描述

三、ipcs 命令 – 查看信号量、消息队列和共享内存

ipcs :

在这里插入图片描述
运行./a& ./b& 之后
在这里插入图片描述
其中4d2,为1234
对应代码semid=semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);

在这里插入图片描述

ipcs -s :只查看信号量

在这里插入图片描述

ipcs -m :只查看共享内存

在这里插入图片描述

ipcs -q :只查看消息队列

在这里插入图片描述

ipcrm -s 编号 :删除信号量


http://chatgpt.dhexx.cn/article/oOHS6lyM.shtml

相关文章

Linux ipcs命令与ipcrm命令的用法详解

转载地址&#xff1a;http://www.jb51.net/article/40805.htm linux/uinx上提供关于一些进程间通信方式的信息&#xff0c;包括共享内存&#xff0c;消息队列&#xff0c;信号 ipcs用法 ipcs -a 是默认的输出信息 打印出当前系统中所有的进程间通信方式的信息 ipcs -m 打印出…

ipcs命令详解——共享内存、消息队列、信号量定位利器

多进程间通信常用的技术手段包括共享内存、消息队列、信号量等等&#xff0c;Linux系统下自带的ipcs命令是一个极好的工具&#xff0c;可以帮助我们查看当前系统下以上三项的使用情况&#xff0c;从而利于定位多进程通信中出现的通信问题。目前也有一些帖子介绍ipcs命令的使用方…

(1)IPC简介

Unix/Linux IPC简介 简述1. 消息传递演变过程2. 同步形式演变 进程、线程与信息共享IPC对象的持续性名字空间fork、exec和exit对IPC对象的影响总结参考资料 简述 IPC是进程间通信(interprocess communication)的简称。用来描述运行在一个操作系统之上的不同进程间各种消息传递…

Linux——信号量(定义、示例、信号量接口、ipcs命令)

目录 1、信号量 2、信号量举例 3、信号量的接口 4、通过控制进程来完成打印机操作 5、ipcs命令 1、信号量 &#xff08;1&#xff09;定义:​​​​​​ ​信号量是一个特殊的变量&#xff0c;一般取正数值。它的值代表允许访问的资源数目&#xff0c;获取资源时&#xff…

什么是IPC?

目录 IPC的简介&#xff1a; IPC的主要功能模块&#xff1a; IPC信号处理过程&#xff1a; IPC硬件构成&#xff1a; IPC的简介&#xff1a; IPC&#xff1a;是IP Camera的简称。它是在前一代模拟摄像机的基础上&#xff0c;集成了编码模块后的摄像机。它和模拟摄像机的区别…

IPC是什么?

IPC是什么&#xff1f; ipc是IP Camera的缩写词&#xff0c;IP是网际协议&#xff0c;Camera是照相机、摄影机&#xff0c;IP Camera顾名思义就是网络摄像机&#xff0c;它是一种由传统摄像机与网络技术结合所产生的新一代摄像机。 网络摄像机又叫IP CAMERA&#xff08;简称IP…

linux ipcs命令详解

进程间通信概述 进程间通信有如下的目的&#xff1a;1、数据传输&#xff0c;一个进程需要将它的数据发送给另一个进程&#xff0c;发送的数据量在一个字节到几M之间&#xff1b;2、共享数据&#xff0c;多个进程想要操作共享数据&#xff0c;一个进程对数据的修改&#xff0c…

ipcs 命令

在unix/linux下&#xff0c;查看共享内存、信号量&#xff0c;队列等共享信息 相应的命令是ipcs [-m|-s|-q] -m列出共享内存&#xff0c;-s列出共享信号量&#xff0c;-q列出共享队列 清除命令是 ipcrm [-m|-s|-q] $id -m 删除共享内存&#xff0c;-s删除共享信号量&#xff0…

Linux的IPC命令

进程间通信概述 进程间通信有如下的目的&#xff1a;1、数据传输&#xff0c;一个进程需要将它的数据发送给另一个进程&#xff0c;发送的数据量在一个字节到几M之间&#xff1b;2、共享数据&#xff0c;多个进程想要操作共享数据&#xff0c;一个进程对数据的修改&#xff0c;…

Linux--ipcs、共享内存、共享接口简介

1.ipcs命令 ipcs -s: 只查看信号量 ; ipcs -m: 只查看共享内存 ; ipcs -q: 只查看消息队列 ; 删除信号量 : ipcrm -s 编号 ; 2.共享内存 共享内存为多个进程之间共享和传递数据提供了一种有效的方式。共享内存是先在物 理内存上申请一块空间&#xff0c;多个进程可以将其…

Linux系统中ipcs命令的使用

ipcs命令的学习 多进程间通信常用的技术手段包括共享内存、消息队列、信号量等等。 ipcs 命令的用途主要用于报告进程间通信设施状态。 ①查看帮助&#xff1a; ipcs -help ②查看所有资源&#xff08;设施&#xff09;&#xff1a; ipcs -a 或 ipcs ③三类资源单独查看方式 …

C++的access()函数

文章目录 函数功能头文件函数原型参数说明示例access函数详解 函数功能 确定文件是否存在或者判断读写执行权限&#xff1b;确定文件夹是否存在即&#xff0c;检查某个文件的存取方式&#xff0c;比如说是只读方式、只写方式等。如果指定的存取方式有效&#xff0c;则函数返回…

access数据库

经过连续几天的学习&#xff0c;初步了解access数据库。以下是知识点的总结&#xff0c;对应刚刚学习的人会很有帮助。 ADO.NET是数据的访问架构 它主要包括 connection,command,datareader,dataadapter,dataset,datatable等六个对象 一、connection 作用&#xff1a;连接数…

Access数据库对象包括哪六个?Access与 Excel 最重要的区别是什么?

我们知道微软有两款经典的数据处理软件&#xff1a;Excel和Access。 由于在运行大量数据时&#xff0c;Excel会卡得让你怀疑人生&#xff0c;Access却轻松运转。所以很多人说他俩的时候&#xff0c;大都总结&#xff1a; “小规模数据用Excel&#xff0c;大规模数据用Access。…

access/_access函数

Linux下 1&#xff0c;头文件&#xff1a; #include <unistd.h>2&#xff0c;函数的声明&#xff1a; int access(const char *pathname, int mode);3&#xff0c;函数的作用&#xff1a; access函数用来判断指定的文件或目录是否存在(F_OK)&#xff0c;已存在的文件或…

Linux access函数讲解

函数&#xff1a; #include<unistd.h> int access(const char* pathname, int mode); 参数介绍&#xff1a; pathname 是文件的路径名文件名 mode&#xff1a;指定access的作用&#xff0c;取值如下 F_OK 值为0&#xff0c;判断文件是否存在X_OK 值为1&#xff0c;判…

C语言中access/_access函数的使用

在Linux下&#xff0c;access函数的声明在<unistd.h>文件中&#xff0c;声明如下&#xff1a; int access(const char *pathname, int mode); access函数用来判断指定的文件或目录是否存在(F_OK)&#xff0c;已存在的文件或目录是否有可读(R_OK)、可写(W_OK)、可执行(X…

C语言:access函数的使用

C语言&#xff1a;access函数的使用 一、access()函数用来判断用户是否具有访问某个文件的权限(或判断某个文件是否存在). 二、需要包含#include<unistd.h> 三、参数和返回值 int access(const char *pathname,int mode) 参数: pathname:表示要测试的文件…

gremlin

g.V().hasLabel(Person).outE(Knows) inE()

复杂Gremlin查询的调试方法

复杂Gremlin查询的调试方法 摘要: Gremlin是图数据库查询使用最普遍的基础查询语言。Gremlin的图灵完备性&#xff0c;使其能够编写非常复杂的查询语句。对于复杂的问题&#xff0c;我们该如何编写一个复杂的查询&#xff1f;以及我们该如何理解已有的复杂查询&#xff1f;本文…