PIPE、SIGNAL(day11)

一、管道
管道分为两种:   无名管道    有名管道
无名管道用于具有亲缘关系的进程间通讯。无名管道是单工的。
有内核管理的一块内存空间。
使用管道,系统提供了pipe(2)
#include <unistd.h>
int pipe(int pipefd[2]);
功能:创建管道
参数:
pipefd[2]:用于返回管道的两端。pipefd[0]指向管道的读端。
pipefd[1]指向管道的写端。

返回值:
0  成功。
-1  错误  errno被设置

使用管道实现两个进程间的通讯。
步骤:
(一)、父进程创建管道
(二)、父进程创建子进程(子进程继承了父进程的文件描述符)
(三)、父进程负责的工作
1、关闭读端
2、通过管道的写端文件描述符,写数据到管道空间。
3、阻塞等待子进程的结束。子进程结束的时候,收尸

(四)、子进程负责的工作
1、关闭写端
2、从管道中读取数据
3、将读取到的数据,输出到显示器
4、结束进程。

代码的实现    pipe.c

有名管道
有名管道其实是一个文件,这个文件只能用于两个进程间通讯的桥梁。不存储任何数据内容。
如何创建一个有名管道的文件。使用mkfifo(3)
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
功能:创建一个有名管道文件
参数:
pathname:指定了有名管道文件的名字
mode:指定了管道文件的权限   mode & ~umask
返回值:
0  成功
-1  错误  errno被设置

编码实现管道文件的创建。  文件名字由命令行第一个参数传入,权限为0664.
代码参见  mkfifo.c
编写代码向有名管道写数据。代码参见PA.c
编写代码实现从有名管道读取数据  代码参见PB.c

进程结束了。  尝试将管道添加到psh中

二、信号的基础
什么是信号?
信号就是软中断。
软中断就是软件模拟的中断机制。
中断又是什么?
正常的执行流程、中断处理程序

正常的执行流程、信号处理程序是两条执行路线,但是属于同一个进程。
系统为我们提供了哪些信号呢?
kill -l

信号有名字和编号。

信号的产生到消失的过程。
信号的产生、信号阻塞、信号递达进程、信号处理
信号的未决状态   就是信号产生了,但是信号还没有被进程处理,这期间,信号的状态为未决状态。

进程可以设置对信号的阻塞。

三、改变信号的处理函数
进程对信号的处理有默认动作。默认处理是终止进程。
除此之外,还有两种  忽略信号    用户自定义
进程从父进程继承信号处理函数。
SIG_DFL   默认    
SIG_IGN   忽略
doit     用户自定义的信号处理函数

系统提供了signal(2) 用来改变信号的处理函数
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t  signal(int signum, sighandler_t handler);
功能:
参数:
signum:指定了信号的编号
handler:指定了signum信号的处理函数
 SIG_IGN, SIG_DFL, 用户自定义函数
返回值:
SIG_ERR   错误
返回的是旧的信号处理函数的地址

typedef void (*sighandler_t)(int);

举例说明   编码实现进程忽略2号信号   代码参见signal2.c
编码实现进程对2号信号的处理采用用户自定义的函数。
代码参见   signal_2u.c


四、信号的产生
信号产生的三种形式:
1、硬件产生信号    ctrl+c    ctrl+
2、使用命令为进程发送信号    kill -信号编号   pid
3、使用库函数或者系统调用为进程发送信号
kill(2)
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
功能:给一个进程发送信号
参数:
pid:指定了接收信号的进程的pid
sig:指定了具体的信号
返回值:
0  成功
-1  错误  errno被设置

举例说明   编写代码实现kill命令的功能。代码参见pkill.c

raise(3)
#include <signal.h>
int raise(int sig);
功能:发送信号给当前进程
参数:
sig:指定信号的编号
返回值:
0  成功
非0   错误

举例说明,使用raise给当前进程发送信号   代码参见 raise.c

alarm(2) 产生SIGALRM信号
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:产生SIGALRM信号,将这个信号发送给当前进程
参数:
seconds:指定了闹钟的时间。如果这个参数为0.取消闹钟。

返回值:
返回剩余的没执行的时间值。

举例说明   编写代码实现每一秒钟输出的数字。代码参见  count.c

五、信号阻塞和未决信号

信号集类型 sigset_t

系统对sigset_t 类型进行了封装

#include <signal.h>
int sigemptyset(sigset_t *set);
功能:初始化信号集为空,不包含任何信号
参数:
set:指定要初始化的信号集
返回值:
0  成功
-1 错误

int sigfillset(sigset_t *set);
功能:初始化信号集为满,包含所有的信号
参数:
set:指定要初始化的信号集
返回值:
0  成功
-1 错误

int sigaddset(sigset_t *set,int signum);
功能:添加指定的信号到信号集
参数:
set:指定信号集
signum:指定信号
返回值:
0  成功
-1 错误

int sigdelset(sigset_t *set,int signum);
功能:从指定信号集删除指定的信号
参数:
set:指定信号集
signum:指定信号
返回值:
0  成功
-1 错误

int sigismember(const sigset_t *set, int signum);
功能:测试信号是否是集合的一员
参数:
set:指定信号集
signum:指定信号
返回值:
-1  错误
10 不是

通过sigprocmask(2)设置信号集为进程的屏蔽字。
#include <signal.h>
int sigprocmask(int how,const sigset_t *set,
         sigset_t *oldset);
功能:检查或者改变阻塞信号
参数:
how:
SIG_BLOCK:原来的set和set的并集
SIG_UNBLOCK:将set集合中的信号从当前进程的set中移除。
SIG_SETMASK:将set设置为当前进程的信号屏蔽字

set:新的信号屏蔽字。
oldset:保存进程原来的信号屏蔽字。如果为NULL,不保存。
返回值:
成功  0
-1  错误

举例说明   编写代码实现对2号信号的阻塞。
代码参见  blocked2.c

多次发送2号信号,进程对2号信号阻塞,在解除阻塞的时候,信号处理函数只执行一次,造成了信号的丢失。这样的信号叫不可靠信号。 1~31

34~64   称为可靠信号,不会有信号丢失。

检测进程的未决信号
sigpending(2)
#include <signal.h>
int sigpending(sigset_t *set);
功能:检测未决信号
参数:
set:未决信号掩码被存放在这个集合中
返回值:
成功  0
错误 -1

举例说明   检测进程的未决信号集
代码参见  pending.c


总结:
一  管道 (无名管道   有名管道)
二、信号基础
三、信号的处理
signal(2)
四、信号的产生
五、信号阻塞和未决信号
原文地址:https://www.cnblogs.com/Kernel001/p/7732616.html