Linux应用软件编程(多任务:进程间通信)
一.进程间通信
同一主机下:
(1)无名管道:pipe (2)有名管道:fifo (3)信号:异步通知机制
(4)共享内存:效率最高 (5)消息队列 (6)信号量集(信号灯):进程间同步
不同主机下: 网络套接字
二.管道(用于同步通信)
无名管道:用于同一主机下,具有亲缘关系的父子进程间通信。
有名管道:用于同一主机下,任意进程间通信。
(1)无名管道
1. 创建一个无名管道并打开
int pipe(int pipefd[2]);
功能:
参数:
pipefd:
pipefd[0] : 管道的读端
pipefd[1] : 管道的写端
返回值:
成功:0;
失败:-1
2. 读管道:read 3. 写管道: write 4. 关闭管道: close
5.void *memset(void *s, int c, size_t n); 将内存清成指定字节
无名管道的特性:
1. 默认64K大小
2. 管道存储数据时,按照FIFO(队列)的方式存储。
3. 写阻塞:管道读写端都存在时,向管道中写入数据,当管道满时,发生写阻塞。
读阻塞:管道读写端都存在时,从管道中读数据,如果管道中有数据,read返回实际读到的字节数;(如果管道中无数据,read发生读阻塞)
读到0:管道的写端关闭,只保留读端,从管道读数据,若有数据,则读到数据,
若无数据,则read返回0,不阻塞。
管道破裂:管道的读端关闭,只保留写端,向管道中写入数据,发生管道破裂(异常)
(2)有名管道
1. 创建管道文件
int mkfifo(const char *pathname, mode_t mode);
2. 打开管道文件 : open (读端和写端必须同时打开)
3. 读写管道文件 : write/read
4. 关闭管道文件 :close
5. 删除管道文件 : remove
三.信号(进程间的异步通知(通信)机制 软中断)
1. 信号类型(用kill -l查看 )
常见信号类型:
2) SIGINT:ctrl + c
让一个进程被打断
3) SIGQUIT:ctrl + \
让一个进程结束
9) SIGKILL:
强制让一个进程结束
11)SIGSEGV:
让一个进程结束(段错误)
13)SIGPIPE:
让一个进程结束(管道破裂)
14)SIGALRM:
让一个进程结束(定时时间到达)
17)SIGCHLD:
子进程结束时发送给父进程
18)SIGCONT:
让停止态的进程继续执行
19)SIGSTOP:
让运行态的进程进入停止态(暂停)强制停止
20)SIGTSTP:
ctrl + z 让进程进入暂停态,后台进程
来自终端的停止信号
用户自定义信号 :SIGUSR1 SIGUSR2
管理员信号:无法被捕获和忽略( 9 SIGKILL 19 SIGSTOP )
2. 接收信号
1. 忽略:不处理
2 .捕获:按照用户自定义方式处理
3. 缺省:按照信号默认方式处(若不注册)
(1)注册信号处理函数
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
功能:信号的接收方,注册一个信号处理函数
参数:
signum:注册的信号的编号
handler:
SIG_IGN : 以忽略方式处理
SIG_DFL: 以缺省方式处理
函数的地址:以捕获方式处理
返回值:
失败:SIG_ERR
3. 发送信号:
int kill(pid_t pid, int sig);
功能:给指定进程发送信号
参数:
pid:进程pid号
sig:发送的信号编号
int pause(void);
功能:挂起当前进程 (S:可中断睡眠状态)
可以通过发送信号的方式,唤醒pause挂起的进程,信号必须被捕获。
unsigned int alarm(unsigned int seconds);
功能:
间隔seconds秒后给调用进程发送一个SIGALRM信号
四.共享内存
内存映射:避免数据的反复读写拷贝,提高了效率。
0.获取一个IPC的key值
key_t ftok(const char *pathname, int proj_id);
功能:获取IPC的key值
参数:
pathname:路径 proj_id:项目ID
返回值:成功:key 失败:-1
1.创建共享内存
int shmget(key_t key, size_t size, int shmflg);
功能:根据key值创建共享内存
参数:
key:IPC的key值
size:共享内存大小(向上取整到页大小的整数倍)(PAGE-SIZE 4096)
shmflag:对对象内存的操作
IPC_CREAT | 0664 (创建)
返回值:成功:共享内存的ID 失败:-1
2.建立共享内存和用户空间的映射关系
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:建立内存映射
参数:
shmid:共享内存的id
shmaddr:映射的用户首地址
NULL:让操作系统自己寻找用户空间,返回空间首地址
shmflg:!SHM_RDONLY(可读可写)
返回值:成功:映射的用户空间首地址 失败:NULL
3.写数据
4.读数据
5.解除映射关系
int shmdt(const void *shmaddr);
功能:解除用户映射关系,释放空间
6.删除共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:控制共享内存
参数:
shmid:共享内存id
cmd:IPC_RMID :删除
buf:删除不需要使用(NULL)
五.消息队列
1.获取IPC通信的key值
key_t ftok(const char *pathname, int proj_id);
功能:获取IPC的key值
参数:
pathname:路径 proj_id:项目ID
返回值:成功:key 失败:-1
2.创建消息队列
int msgget(key_t key, int msgflg);
功能:根据key值创建一个消息队列
参数:
key:IPC的key值
msgflg:标志位 IPC_CREAT|0664
返回值:成功:消息队列的id号 失败:-1
3.发送消息
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:向消息队列中发送信息
参数:
msqid:消息队列的id
msgp:要发送的消息的结构体首地址
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
msgsz:消息体中正文内容大小
msgflg:标志位:默认0
返回值:成功:0 失败:-1
4.接受消息
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
功能:从消息队列中接受信息
参数:
msqid:消息队列的id
msgp:存放接收到的消息的结构体首地址
msgsz:接收的消息体中正文内容大小
msgtyp:消息的类型
返回值:成功:实际读到的正文的字节数 失败:-1
5.删除消息队列
int msgctl(int msqid, int cmd, struct msqid_ds *buf);