1、linux进程间通讯
继承unix进程间通讯:管道 信号
AT&T :system V IPC 通讯进程只能在单个计算机 :信号量 消息队列 共享内存
BSD:形成了基于socket的进程间通讯机制 TCP/IP
2、管道
(1)无名管道:父子进程
#include <unistd.h>
int pipe(int pipefd[2]);
创建一个管道
fd[0]:读端
fd[1]:写端
返回值:
0:成功
-1:失败
注意:(1)当管道已经满了 write pipe 会阻塞
(2) 当管道为空 read pipe 会阻塞
(2)有名管道:任何进程之间
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
3、信号
信号在软件层次上对中断的一种模拟 异步通讯方式
中断:对cpu上的中断 (硬件)
信号:对进程的中断 (软件)
(1)信号的来源
(1)程序执行错误 如 内存访问越界
(2)其他进程发送
(3)通过控制终端发送 ctrl + c;
(4)子进程结束向父进程发送信号 SIGCLD
(5)定时器SIGALRM
(2)信号
kill -l 查看当前系统所有的信号
(3)信号处理方式
忽略信号:对信号不做任何处理
捕捉信号:定义处理函数 当信号发生的时候 执行相应的处理函数
缺省操作:在linux系统中间都规定了默认操作
(4)信号的发送与捕捉
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
pid:接受信号的进程的PID
sig:信号
返回值:0:成功
-1:出错
int raise(int sig);
//kill(getpid(),SIGSTOP);
给进程本身发送信号
(5)定时器的信号捕捉
unsigned int alarm(unsigned int seconds);
进程定时器
定时时间到 发送SIGALRM
SIGALRM:默认操作:终止进程
返回值:
在调用之前 如果已经设置过闹钟 返回上一次的剩余时间
否则返回0
-1:出错
int pause(void);
暂停进程
当收到信号时 会唤醒进程继续执行
(6)信号处理
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
参数:
signum:信号
handler:SIG_IGN:忽略该信号
SIG_DFL:采用默认方式处理信号
自定义的信号处理函数的指针
返回值:返回一个指向信号处理函数的地址
1)父进程捕捉子进程的信号
2)从终端输入文字再次输出到终端,如果3s没有输入就输出提示
//SIGALRM
alarm()和signal()
4、信号的阻塞处理
(1)通知系统内核停止向进程发送指定的信号
(2)内核对进程接收到的相应的信号进行缓存
(3)当进程解除相应的信号的阻塞
设置阻塞的原因:
(1)正在执行信号处理函数时有其他的信号到来
(2)信号处理函数和其他进程对某个共享区域进行读写
sigset_t:信号集
int sigemptyset(sigset_t *set);
把信号集合清空
int sigfillset(sigset_t *set);
把信号集合填满
int sigaddset(sigset_t *set, int signum);
把对应的信号加到阻塞信号集合中
int sigdelset(sigset_t *set, int signum);
把对应的信号从阻塞信号集合中删除
int sigismember(const sigset_t *set, int signum);
判断信号是否是在阻塞信号集合中
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
//设置阻塞信号集合
how:设置信号阻塞掩码的方式
SIG_BLOCK:阻塞信号集
SIG_UNBLOCK:解除信号集
SIG_SETMASK:设置阻塞掩码
oldset:旧的阻塞集合
int sigpending(sigset_t *set);
//获取阻塞的信号 未决信号
int flag = 0;
int flag = 1;
while(flag == 0){
int sigsuspend(const sigset_t *mask);
}
//等待信号
(1)设置信号掩码并阻塞进程
(2)收到信号 恢复原来的屏蔽字
(3)调用进程设置的信号处理函数
(4)等待信号处理函数返回后 sigsuspend()返回
原子操作
pause() -----等待信号(阻塞的信号除外)
5、消息队列
(1)消息的列表
队列ID
消息ID
(2)创建
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
key:指定的ID来生成队列ID key:ftok()通过转换文件来获取
msgflg:IPC_CREAT:创建新的消息队列
IPC_EXCL:存在报错
IPC_NOWAIT:非阻塞
返回值:返回队列ID
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
功能:获取key
pathname:文件名---->inode节点号
proj_id:自己指定
由inode节点号和proj_id合成
65538:0x10002
38:0x26
key: 0x2610002
(4)接收消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
参数:
msqid:消息队列ID ----- msgget()
msgp:消息的缓冲区
msgsz:消息结构的大小
msgtyp:0:接收消息队列中的第一个消息
大于0:接收消息队列中第一个为msgtyp的消息
小于0:接收消息队列中第一个不小于msgtyp的绝对值由最小的消息
msgflg:
0:忽略
MSG_NOERROR:接收的消息大于size 则消息就会截短到size字节 不通知消息发送进程
IPC_NOWAIT:没有指定类型的消息 就会返回错误ENOMSG
返回值:实际接收的字节数
会删除对应的消息
(5)发送消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数:
msqid:消息队列ID ----- msgget()
msgp:发送的消息缓冲区
struct msgbuf{
long mtype;//消息类型
char mtext[1];//消息内容
};
msgsz:消息内容的大小
msgflg:
IPC_NOWAIT:发送条件不满足的时 就会立即返回
a):队列消息已经满了
创建2个子进程 父进程负责发送 子进程1:发送类型为1的消息 子进程2:发送消息类型为2的消息
子进程1接收类型为1的消息
子进程2接收类型为2的消息
(5)控制函数
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
msqid:消息队列ID
cmd:
IPC_STAT:获取struct msqid_ds结构 保存到buf
IPC_SET:设置struct msgqid_ds结构
IPC_RMID:删除消息队列
buf:存储struct msqid_ds结构
返回值:成功:0(IPC_STAT,IPC_SET,IPC_RMID)
失败:-1