Linux系统编程--信号与管道

1、信号与管道是什么?

首先了解信号与管道的意义,我们需要了解Linux系统中进程之间是如何通信的。Linux操作系统下,以进程为单位来分配或者管理资源,进程之间不能直接访问资源,因此,要求进程间的资源和信息共享就意味着进程之间能够相互通信。这就是通信机制:信号、管道。

2、进程通信的目的?

数据传输、共享数据、通知事件、资源共享、进程控制

3、何为通信机制?

了解该机制需要明白进程是如何来互相通信的,Linux支持多种进程间的通信,IPC机制,包括共享内存、消息队列、信号量、网络通信。

好了,介绍完这些需要了解的知识后进入正题!

一、信号

信号是一种异步的通知机制,用于在软件层面模拟中断机制。当一个进程收到信号时,其行为类似于处理器接收到一个中断请求,信号属于一种软中断方式

操作:

1.查看信号:kill -l

不可靠信号:1-31

可靠信号:34-64

9 号(SIGKILL),19 号(SIGSTOP) 不允许被忽略,也不允许被改造

杀死进程:Ctrl + C [ (2)、SIGINT ]

                  Ctrl + \  [ (3)、SIGQUIT ]

                KILL [ (9)、SIGKILL ]  kill-sig pid   sig信号

内核:当我们的程序出现一些错误的时候,例如段错误等,内核会给我们的进程发送杀死当前进程的信号。

程序:通过函数发送信号:kill

2、给进程发送信号:kill
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
形参:
        pid -- 你要给哪一个进程发送信号
        sig -- 信号(可以写编号,也可以写后面的宏定义)
返回值:
成功返回 0,失败返回-1
特殊信号:
        9 -- SIGKILL -- 杀死进程,不可以被忽略或者改造;
        14 -- SIGALRM -- 闹钟信号,杀死进程
        17 -- SIGCHLD -- 只要子进程状态发生改变,父进程就能接收到该信号
        18 -- SIGCONT -- 恢复 19 号 信号 暂停 的进程
        19 -- SIGSTOP -- 暂停进程
3、给自己发送信号:raise
#include <signal.h>
int raise(int sig);
形参:
sig -- 信号
等价于:
kill(getpid(),sig);
4、计时杀死进程:alarm
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
形参:
seconds 秒数
功能:
设置闹钟,闹钟事件到,产生闹钟信号,闹钟信号默认杀死当前进程;
如果在该 alarm 之前,已经设置过闹钟,此时闹钟会给更新
返回值:
如果上一次设置的有闹钟,返回上一个闹钟的剩余时间,否则返回 0;
5、产生信号再接触阻塞状态:pause
#include <unistd.h>
int pause(void);
只要运行,就阻塞,直到有一个信号产生,才会解除阻塞
6、信号处理函数:signal
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
形参:
signum -- 要处理的信号
handler -- SIG_DFL -- 默认处理
-- SIG_IGN -- 忽略处理
-- 函数 指针 -- 捕获到该信号,执行函数指针对应的函数
具体用法:
signal(2,SIG_DFL); 默认处理
signal(2,SIG_IGN); 忽略处理
signel(信号,Fun);
捕获到信号,执行 Fun 函数
7、注册退出清理函数:atexit
#include <stdlib.h>
int atexit(void (*function)(void));
//形参:函数指针
void Clean(void)
{
printf(“%s 被运行\n”,__FUNCTION__);
}
int main()
{
atexit(Clean);//注册退出清理函数,在 main 函数退出的时候,直到自动运行 Clean 函数
}

二、管道

管道(Pipe)是一种常见的进程间通信(IPC)机制,它允许两个进程通过一个半双工的通道进行数据传输。它作为两个进程之间的数据传输媒介。管道的一端连接一个写进程,另一端连接一个读进程

创建和使用

  • 创建匿名管道通常使用pipe()系统调用。
  • 使用fork()创建子进程后,父进程写入管道,子进程从管道中读取数据。
  • 写入管道通常使用write()系统调用,而读取管道通常使用read()系统调用。

管道的特点:

属于半双工通信
管道正常的情况下,管道中没有内容, read 会阻塞;写端关闭
管道文件和普通的文件的区别:
管道的内容,一旦读走,就没有了
管道文件不允许使用 lseek 等光标偏移的函数
管道一定遵循先进先出的原则
管道有大小:
64k   64 * 1024 = 65536 字节
1、无名管道
适用于父子进程之间的通信;
没有名字的管道,没有 真正的介质文件存在 仅仅以 文件描述符 的形式可以让我们操作
创建:pipe
#include <unistd.h>
int pipe(int pipefd[2]);
形参:
pipefd -- 整型数组,2 个元素
pipe fd[0] :存放的管道的 读端 的文件描述符
pipe fd[1] :存放的管道的 写端 的文件描述符
返回值:
成功返回 0,失败返回-1;
用法:
int fd[2] = {0};
pipe(fd);  fd[0]  fd[1]
创建子进程,也得有管道
问题:先创建子进程还是先创建管道?
先创建管道,子进程复制父进程资源(包含管道),

2、有名管道(记忆)

适用于任意两个进程

1. 创建管道文件 .fifo
2. 打开管道文件 open
3. 读写 write read
4. 关闭 close
3、创建管道文件:mkfifo
#include <sys/stat.h>
#include<sys/types.h>
int mkfifo(const char * pathname,mode_t mode)
参数
pathname:要创建的 FIFO 文件的名字(路径+名字 以.fifo 结尾)
mode: 创建的 FIFO 文件的权限
真正的权限:mode &(~umask)
返回值
成功返回 0,失败(如果管道文件原本存在,直接返回失败)返回-1。
4、打开管道文件:open
int fd = open(char *pathname,int flag);
flag 只能在 O_RDONLY 和 O_WRONLY 中选择其一;
open 函数在打开管道文件的时候,必须两方都执行 open,open 才能打开,只有一个进程执行 open,open 会发生阻塞,直到另外的一个进程也运行到 open 的位置,两方同时解除阻塞
5、有名管道的删除:unlink
int unlink(const char * pathname)
#include <unistd.h>
参数
pathname:要删除的 FIFO 文件的名字(带路径)
返回值:
成功返回 0,失败返回-1。

  • 31
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值