Linux系统编程 | 进程间通信

💓个人主页:mooridy
💓专栏地址:Linux
关注我🌹,和我一起学习更多计算机的知识!

🔝🔝🔝

管道

管道分为匿名管道和命名管道

匿名管道

你怎样理解匿名管道?

这里管道我理解为内核里的一串缓存,一个进程从一边写,另一个进程从另一边读

匿名管道有什么特点呢

1.适用于父子进程之间的通信
2.只适用于单边通信
3.管道传输的数据是无格式并且大小受限的

匿名管道函数?
int pipe(fd[2]);   //fd[0]是读端,fd[1]是写端
匿名管道原理?

我们可以让父进程通过fork函数创建出子进程后,子进程会写时拷贝一份和父进程一模一样的PCB,其中肯定就包括了相同的文件描述符,文件描述符一样后肯定就会指向相同的文件。那么这时比较混乱,因为同时有两个读端两个写端指向同一个文件嘛,所以我们通常会选择保留父进程写端,和子进程读端,就实现出匿名管道了。

匿名管道通信的四种情况?

读正常 && 写满:

  • 写操作会被阻塞,直到管道中有空间可用。而读操作正常进行时,它会从管道中读取数据,每读取一部分数据,管道中就会空出相应的空间,当管道中有空间时,被阻塞的写操作就会继续执行,继续向管道中写入数据。

写正常 && 读空:

  • 当管道为空且读操作试图从管道中读取数据时,读操作会被阻塞,直到有数据被写入管道中。而写操作正常进行时,一旦有数据写入管道,被阻塞的读操作就会被唤醒,开始从管道中读取数据。

写关闭 && 读正常:

  • 当写端关闭后,读端在读取完管道中剩余的数据后,再进行读操作时,read 函数会返回 0,表示管道中已经没有数据可读,且写端已经关闭。这是一种正常的通信结束的情况,读端可以根据返回值 0 来判断通信是否结束。

读关闭 && 写正常:

  • 当读端关闭后,如果写端继续向管道中写入数据,会引发 SIGPIPE 信号。默认情况下,进程接收到 SIGPIPE 信号后会终止。
使用管道如何双方通信?

建立两个管道。

命名管道

如何理解命名管道?

命名管道的本质就是一种特殊类型的文件

命名管道有什么特点呢?

1.适用于任意两个进程之间
2.对传输的数据没有格式要求,但有大小限制
3.单边通信

命名管道函数?
int mkfifo(const char* filename,mode_t mode);

消息队列

如何理解消息队列?

消息队列本质是内核中的消息链表。
它很想发电子邮件,A进程往B的消息队列中发入信息,A进程就可以走了,B进程需要数据时再去读取即可。

消息队列有什么特点呢?

1.附件大小有限制,每个消息体的大小固定,发送前两个进程就已经约定了消息体的格式
2.通信不及时,用户态和数据态之间会发生多次数据拷贝,影响效率。

共享内存

如何理解共享内存?

本质就是两个进程的分别的某块虚拟内存映射到同一块物理内存上

共享内存的特点

1.效率快,进程间的数据传递无需执行进入内核的系统调用
2.可能发生多个进程同时修改物理内存中的数据的问题

共享内存函数

shmget

功能:⽤来创建共享内存
原型
int shmget(key_t key, size_t size, int shmflg);
参数
key:这个共享内存段名字
size:共享内存⼤⼩
shmflg:由九个权限标志构成,它们的⽤法和创建⽂件时使⽤的mode模式标志是⼀样的
取值为IPC_CREAT:共享内存不存在,创建并返回;共享内存已存在,获取并返回。
取值为IPC_CREAT | IPC_EXCL:共享内存不存在,创建并返回;共享内存已存在,出
错返回。
返回值:成功返回⼀个⾮负整数,即该共享内存段的标识码;失败返回-1

shmat

功能:将共享内存段连接到进程地址空间
原型
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数
shmid: 共享内存标识
shmaddr:指定连接的地址
shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回⼀个指针,指向共享内存第⼀个节;失败返回-1
说明:
shmaddr为NULL,核⼼⾃动选择⼀个地址
shmaddr不为NULL且shmflg⽆SHM_RND标记,则以shmaddr为连接地址。
shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会⾃动向下调整为SHMLBA的整数倍。
公式:shmaddr - (shmaddr % SHMLBA)
shmflg=SHM_RDONLY,表⽰连接操作⽤来只读共享内存

shmdt

功能:将共享内存段与当前进程脱离
原型
int shmdt(const void *shmaddr);
参数
shmaddr: 由shmat所返回的指针
返回值:成功返回0;失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段

shmctl

功能:⽤于控制共享内存
原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
参数
shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作(有三个可取值)
buf:指向⼀个保存着共享内存的模式状态和访问权限的数据结构
返回值:成功返回0;失败返回-1
命令说明
IPC_STAT把 shmid_ds 结构中的数据设置为共享内存的当前关联值
IPC_SET在进程有足够权限的前提下,把共享内存的当前关联值设置为 shmid_ds 数据结构中给出的值
IPC_RMID删除共享内存段

信号量

信号量是什么?

信号量本质相当于一个表示可使用资源数量的计数器,它的作用是实现进程间的互斥与同步,本质是对资源的一种预定机制

信号量具体操作?

信号量有两个操作:P操作和V操作
P操作,计数器++,申请资源
V操作,计数器–,释放资源

信号

信号是什么?

信号是程序发生异常时的一种异步响应机制

信号产生的原因有哪些?

1.硬件中断 除零,内存越界
2.软件条件
如果读端进程关闭了管道的读端,而写端进程还在向管道写入数据,那么写端进程就会收到 SIGPIPE 信号。
3.通过终端按键产生信号 e.g. CTRL+C
4.调用系统命令 kill -9 [pid]
5.使用函数产生信号 kill函数 raise 函数 abort 函数

收到信号和怎么处理?

1.执行默认动作
3,自定义捕捉信号
3.忽略信号
其中SIGKILLSIGSTOP不能被自定义或者忽略

进程如何保存信号的?

几个概念

信号递达:
实际执行处理信号的动作叫做信号的递达

信号的未决状态(pending):
在信号产生到信号递达之间的状态叫做信号的未决状态

信号阻塞(block):
一旦一个信号被设置了阻塞之后,那么此进程就不会收到此信号

信号忽略:
一旦一个信号被设置为忽略,那么当这个信号来临后,进程不会对此信号做处理

阻塞和忽略的区别:
一个信号被阻塞后,它就不会递达,而忽略是指信号递达后,执行的动作是什么都不做

进程如何保存信号的?

![[Pasted image 20250320173527.png]]

在进程的PCB中,存在三张和信号相关的表(前两张是位图,最后一张是数组)
block位图:
这个位图代表,在这个进程中,有哪些信号是被阻塞了的?这个位图又被称为信号屏蔽字

pending位图:
这个位图是进程存储信号的结构,位图中的第n个位置为0/1代表是否收到了n号信号,如若收到,会在后续进行处理,这个位图又被称为信号集

handler数组:
首先,这个数组是一个函数指针数组,里面存储的是函数的地址,数组的n号元素存储的函数地址代表收到n号信号之后,要去处理信号时,需要调用的函数.
在上图中,SIG_DFL宏代表这个函数就是此信号的默认处理函数,SIG_IGN宏代表收到这个信号后,直接忽略此信号,当然我们也可以自己写一个函数来充当信号的处理方法,

进程如何捕捉信号的(重点)?

从内核态返回用户态时,会进行信号的检测和处理。
[[Linux系统编程/用户态和内核态]]

  1. 当前正在执⾏ main 函数,这时发⽣中断或异常切换到内核态执行系统调用
  2. 当执行完系统调用后,会回到用户态
  3. 在这期间会进行信号的检测和处理
  4. 如若此时检测到有信号到来,那么会把代码直接跳转到信号处理的函数处
  5. 当信号处理函数返回时还会执行特殊的系统调用,再回到内核态
    ![[Pasted image 20250320174642.png]]

![[Pasted image 20250320175752.png]]

信号相关函数

sighandler 函数返回后自动执行特殊的系统调用 sigreturn 再次进入内核态,主要有以下几方面原因:

  • 恢复信号屏蔽字:在 sighandler 函数被调用时,内核会自动将当前信号加入进程的信号屏蔽字,防止在处理该信号过程中,相同信号再次被处理而导致混乱。当 sighandler 函数返回后,需要通过 sigreturn 系统调用进入内核态,来自动恢复原来的信号屏蔽字,以保证进程后续信号处理的正常逻辑 。比如进程在处理信号 A 时,不想被其他的信号 A 打断,就会在处理期间屏蔽信号 A,处理完后就需要恢复原来的信号屏蔽状态。
  • 检查新信号:进入内核态后,内核可以检查是否有新的信号递达。如果有新的信号,内核会按照相应的规则(如根据信号的处理动作是默认、忽略还是自定义处理函数等)来进行处理;如果没有新的信号要递达,内核才会恢复之前进程被中断处(如 main 函数)的上下文,让进程继续执行后续指令。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值