管道通信:分为无名和有名管道
无名管道:
为了进程间能够通信,调用系统创建管道作为存储空间,以队列模式先进先出,管道头部文件描述符hfd,尾部文件描述符tfd,需要两个进程PCB相同,则PB为PA的子进程,fork创建PB进程继承了PA进程的PCB,也就继承了文件描述符
此管道只能应用于具有亲缘关系的通信,父子或兄弟关系(无名管道不记录在系统当中)
管道里没有内容,读不出来会读阻塞
管道满了,写不进去会写阻塞
创建单向管道
#include<unistd.h>
int pipe(int pipefd[2]);
功能:创建一个单向管道
参数:pipefd[0]指向读端,pipefd[1]指向写端
返回值:成功返回0,失败返回-1,errno被设置
代码测试:
有名管道是一种文件类型的管道,该类型文件的特点是内容始终为0,只起到进程间通讯的作用
有名管道对于进程之间的关系没有要求
使用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被设置
测试结果如下:
信号的基础知识
什么是信号:软中断,软件实现的中断机制,使用中断处理程序
进程再执行过程中,如果有信号到来,进程调用信号处理程序,处理完毕进程继续执行
每个进程都有信号的处理程序,继承父进程
系统为用户提供了多少信号?(kill -l可以查看)
常用
2号信号,终止进程(ctrl+c)
3号信号,ctrl+\
9号信号,杀死进程
10、12自定义
11、段错误信号
14、闹钟信号
17、子进程终止发给父进程的回收资源信号
信号一般经过三个过程,产生、递达、处理
信号的产生
①硬件产生信号 ctrl+c等等
②使用命令产生信号 kill -信号编号
③使用系统调用或库函数发送 kill(2)、raise(3)、alarm(2)
从产生到处理之前信号都处于一个未决状态,称这种信号叫做未决信号,可以设置进程为信号进行阻塞
信号的处理有三种方式
①缺省处理
②忽略处理
③用户自定义处理
信号处理函数的注册signal(2)
#include<signal.h>
typedef void(*sighandler_t)(int);
sighandler_t signal(int signum,sighandler_t handler);
功能:改变进程的信号处理函数
参数:
signum:指定信号编号
handler:指定处理函数
返回值:
错误:返回SIG_ERR,errno被设置
成功:返回原来信号处理函数的入口地址
handler:
①SIG_IGN 信号忽略,SIGKILL和SIGSTOP不可忽略
②SIG_DFL 缺省处理
③自定义函数
其中SIGKILL和SIGSTOP不可忽略
信号的发送
#include<sys/types.h>
#include<signal.h>
int kill(pid_t pid,int sig);
功能:发送信号给进程和进程组
参数:
pid:指定了目标进程的pid
sig:指定了信号编号
返回值
成功返回0
失败返回-1,errno被设置
#include<unistd.h>
unsigned int alarm(unsigned int seconds);
功能:设置一个闹钟,到seconds指定秒时,产生SIGALRM信号,将信号发送给当前进程,默认是终止进程
参数:
seconds 指定的秒数,如果是0,将取消原来设置的所有闹钟,所有未决闹钟都被取消
返回值:
原来无设置闹钟返回0
原来设置闹钟返回闹钟的未决时间
#include<unistd.h>
int pause(void);
功能:等待信号
返回值:当信号到达调用完信号处理函数后再返回-1,errno被设置
注:忽略信号不能唤醒pause,自定义信号可以,pause使用时CPU会被让出,等待信号处理才会唤醒
信号阻塞的设置
信号集类型分为信号掩码集和未决信号集
信号掩码集:用来指示线程阻塞的信号的集合。通俗地讲,信号掩码用来表示哪些信号会被线程阻塞
未决信号集:信号已经产生了,但是还没有成功送达给线程处理的集合
信号集相关操作:
定义一个信号集是sigset_t
#include<signal.h>
int sigemptyset(sigset_t *set);
功能:将信号集初始化为空
参数:set是要指定初始化的信号集地址
返回值:成功返回0,失败返回-1,errno被设置
int sigfillset(sigset_t *set);
功能:将信号集初始化为满,也就是包含所有信号
参数返回值同上
int sigaddset(sigset_t*set,int signum);
功能:将信号添加到信号到信号集中
参数
set 指定信号集
signum 指定信号编号
返回值同上
int sigdelset(sigset_t *set,int signum);
功能:将信号从信号集中移除
参数返回值同上
int sigismember(const sigset_t*set,int signum);
功能:测试信号是否是信号集的一员
参数同上
返回值:
成功:返回1代表是,0代表不是
失败:返回-1,errno被设置
int sigpromask(int how,const sigset_t*set,sigset_t *oldset);
功能:检查和改变阻塞信号集
参数:
set:指定信号掩码集
oldset:如果不为空,将进程原来的信号掩码集保存到这里
how:
SIG_BLOCK:将set和当前进程信号掩码集合并
SIG_UNBLOCK:将set集合中信号从当前进程信号掩码集中移除
SIG_SETMASK:将set设置为进程的信号掩码集
返回值:
成功:返回0
失败:返回-1,errno被设置
int sigpending(sigset_t*set);
功能:审查当前进程的未决信号
参数:
set:将当前进程的未决信号集返回到set指定的地址空间里
返回值:
成功 返回0
失败 返回-1 errno被设置
代码测试:
注:信号的丢失
有些信号在阻塞时输入多次的时候,只会被执行一次,叫做不可靠信号(1-31号信号)
没有信号丢失的称为可靠信号,也叫实时信号(34-64号信号)