Linux进程间通信(Inter-Process Communication, IPC)是指在不同进程之间交换数据或信息的机制。由于进程间不能直接共享内存,Linux 提供了多种 IPC 机制来实现进程间的通信。主要为:管道、信号量、共享内存、消息队列、套接字。
目录
一、管道
1.1 有名管道
1.1.1 创建有名管道文件
1.1.2 进程A打开管道文件写入数据
1.1.3 进程B打开管道文件读取数据
1.1.4 进行通信
1.1.5 管道读写机制分析
1.1.6 注意事项
1.1.7 面试题总结
1.2 无名管道
1.2.1 创建无名管道文件
1.2.2 pipe()使用示例
1.2.3 父子进程利用无名管道进行通信
1.2.4 无名管道使用注意事项
二、信号量
2.1 信号量的基本概念(面试题)
2.2 操作信号量的接口介绍
2.2.1 依赖的头文件
2.2.2 创建一个信号量或者获取一个已经存在的信号量
2.2.3 对信号量进行P或者V操作(加或者减1)
2.2.4 对信号量进行初始化或者删除信号量
2.3 自定义实现对信号量的操作
2.4 信号量控制进程示例:两个进程同时使用打印机资源
2.4.1 题目描述
2.4.2 不进行控制
2.4.2 利用信号量进行控制
2.5 面试题
2.5.1 题目描述
2.5.2 控制思路
2.5.3 代码实现
一、管道
管道可以用来在两个进程之间传递数据,如: ps -ef | grep “bash”, 其中‘|’就是管 道,其作用就是将 ps 命令的结果写入管道文件,然后 grep 再从管道文件中读出该数据进行 过滤。 思考: 如果进程 a 要将从键盘获取的数据循环传递给另一个进程 b, 用已具备的知识思考应该如何完成?
1.1 有名管道
1.1.1 创建有名管道文件
有名管道可以在任意两个进程之间通信,有名管道创建的方式有两种如下:
1.1.2 进程A打开管道文件写入数据
1.1.3 进程B打开管道文件读取数据
1.1.4 进行通信
需要注意:通信的前提是双方都要打开管道! 使用管道文件时,必须要同时打开俩个文件,且必须有一个是只读文件,另一个是只写文件。只打开一个文件,只打开一个只读或只写文件,会阻塞在open管道文件这里,等到另一个文件打开了,才会执行下面。
如何解决呢?再打开另外一个终端。
1.1.5 管道读写机制分析
1.1.6 注意事项
1.1.7 面试题总结
1.2 无名管道
1.2.1 创建无名管道文件
无名管道主要应用于父子进程间的通信。 无名管道的创建如下:无名管道,没有名字,只能靠文件描述符,文件描述符不能给到别的进程,只能fork,让子进程拿到数据。因此,应该先创建无名管道,再fork产生子进程。
1.2.2 pipe()使用示例
1.2.3 父子进程利用无名管道进行通信
利用无名管道进行通信:父进程写入数据,子进程读取数据。
1.2.4 无名管道使用注意事项
二、信号量
2.1 信号量的基本概念(面试题)
信号量(Semaphore)是一种用于同步进程间或线程间访问共享资源的机制。信号量可以用于控制对公共资源的访问,以避免竞争条件和实现互斥。信号量在操作系统中起到非常重要的作用,尤其是在多进程和多线程环境中。
信号量是一种特殊的变量,其值可以用来控制对公共资源的访问。信号量主要有两种类型:
- 计数信号量(Counting Semaphore):值可以是非负整数,表示可用资源的数量。
- 二进制信号量(Binary Semaphore):也称为互斥量(Mutex),其值只能是0或1,主要用于实现互斥访问。
2.2 操作信号量的接口介绍
2.2.1 依赖的头文件
2.2.2 创建一个信号量或者获取一个已经存在的信号量
semget是可以创建信号量也可以获取已经存在的信号量的,第一个参数是key 两个进程想使用同一个信号量,只要key值相同就可以;第二个参数是创建信号量的个数;第三个参数是标志位,创建信号量的权限。
2.2.3 对信号量进行P或者V操作(加或者减1)
semop对信号量进行P操作或者V操作(信号量加一或者减一)。
2.2.4 对信号量进行初始化或者删除信号量
注意:要对这个联合体在头文件sem.h进行声明。
semctl既可以初始化信号量 也能销毁信号量,第一个参数是,创建的信号量的id(semget 创建之后的返回值);第二个参数是信号量的下标,信号量的下标从0开始,如果只有一个信号量就为0;第三个参数是初始化信号量(SETVAL),还是删除一个信号量(IPC_RMID)。注意:如果是删除信号量,它会将所有的信号量进行删除。
2.3 自定义实现对信号量的操作
创建对应的sem.h对信号量的操作函数进行声明,以及对联合体semun进行定义。另外创建sem.c对函数进行具体实现,这样在后面的利用信号量对进程控制时,引入这个头文件,然后直接调用函数即可,非常方便!
static int semid=-1;
void sem_init()
{
semid=semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);//1代表创建一个信号量,IPC_CREAT没有就创建,有就获取。IPC_EXCL有就返回-1,因为创建的时候要初始化,所以要加这个。
if(semid==-1)//跟据返回值判断信号量是否创建过
{
semid=semget((key_t)1234,1,0600);//再次获取这个id的信号量 此时的 1和0600都是占位用的,因为前面创建的时候已经定义过了。
if(semid==-1)
{
printf("semget err\n");//没有空间了,创建不了了
}
}
else
{
union semun a;
a.val=1;//用联合体来初始化信号量的初始值
if(semctl(semid,0,SETVAL,a)==-1)//0代表下标为0的信号量
{
printf("semctl init err\n"); //初始化信号量失败
}
}
}
void sem_p()
{
struct sembuf buf;//创建结构体
buf.sem_num=0;//下标为0,只有一个信号量
buf.sem_op=-1;//对信号量进行-1操作
buf.sem_flg=SEM_UNDO;//防止进程在进行p操作时突然崩掉,信号量就不会释放了,其他进程一直阻塞住,对信号量进行不了操作,系统在进程进行p操作时会记录下来,如果崩掉,系统会把信号量还原。
if(semop(semid,&buf,1)==-1)//这里的1代表只有一个结构体
{
printf("p err\n");
}
}
void sem_v()
{
struct sembuff buf;
buf.sem_num=0;
buf.sem_v=1;
buf.sem_flg=SEM_UNDO;
if(semop(semid,&buf,1)==-1)
{
printf("v err\n");
}
}
void sem_destroy()
{
if(semctl(semid,0,IPC_RMID)==-1)//0是占位用,最后一个加不加结构体地址都无所谓,加了也不看。
{
printf("destroy err\n");
}
}
2.4 信号量控制进程示例:两个进程同时使用打印机资源
2.4.1 题目描述
由于打印机同一时刻 只能被一个进程使用,所以输出结果不应该出现 abab,如何控制呢?
2.4.2 不进行控制
A进程使用打印机资源
B进程使用打印机资源
运行结果
2.4.2 利用信号量进行控制
如何控制?思路?
加入信号量控制的A进程
加入信号量控制的B进程
介绍几个常用命令:
- ipcs 可以查看消息队列 共享内存段 信号量
- ipcs -s 只查看信号量
- ipcrm -s id 删除信号量
利用信号量控制进程之后的结果