信号和共享内存
信号
信号:实现进程间的通知机制
实现进程间的异步通信
软中断
异步通信:接收方不知道什么时候发送方会发送数据。
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 让进程进入暂停态,后台进程
来自终端的停止信号
10) SIGUSR1
12) SIGUSR2
用户可自定义的信号
9) SIGKILL
19) SIGSTOP
管理员信号:只能按照默认方式处理,不能够被忽略和捕获。
当进程收到一个信号,会打断该进程正在执行的任务,处理信号产生的事件;
当该事件处理完时,进程又从原来的位置继续执行。
signal:注册一个信号
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
功能:设置信号的处理方式(注册一个信号)
参数:
signum:要处理的信号的编号
handler:
SIG_IGN: 以忽略方式处理该信号(不处理)
SIG_DFL:以缺省方式处理(系统默认方式)
函数的地址:以捕获方式处理(自定义)
返回值:
失败:NULL
自定义方式:返回自定义的函数入口。
void (*sighandler_t)(int signum);
sighandler_t:执行信号任务处理函数的入口
参数:
signum:触发该任务函数的信号
注意:
1. 若信号不被注册,则按照默认方式处理
2. 信号只需注册一次即可;
3. 每次信号的到来都会触发一次信号任务处理函数;
4. 信号尽可能早注册。
#include <stdio.h>
#include <signal.h>
void handler(int signum)
{printf("%d signal comming\n", signum);
}
int main(int argc, const char *argv[])
{signal(SIGINT, SIG_IGN);
// signal(SIGINT, SIG_DFL);// signal(SIGKILL, handler);while (1){printf("hello world\n");sleep(1);}return 0;
}
3. 发送信号
1)kill 命令
2) kill();
int kill(pid_t pid, int sig);
功能:给指定的进程发送一个信号
参数:
pid:接收信号的进程PID
sig:信号的编号
返回值:
成功:0;
失败:-1;
#include <stdio.h>
#include "head.h"
#include "signal.h"void handler(int signum)
{int i = 3;while(i--){printf("Son is doing homework\n");sleep(1);}
// kill(getppid(), SIGUSR2);exit(0);
}void handler2(int signum)
{printf("%d signal is comming\n", signum);wait(NULL);exit(0);
}int main(int argc, const char *argv[])
{pid_t pid = fork();if (pid > 0){signal(SIGCHLD, handler2);int i = 8;while (i--){printf("Father is working\n");sleep(1);}kill(pid, SIGUSR1);while (1){printf("xxxxxxxxxxxx\n");sleep(1);}}else if (0 == pid){signal(SIGUSR1, handler);while (1){printf("Son is playing games\n");sleep(1);}}else {perror("fork error");}return 0;
}
5)unsigned int alarm(unsigned int seconds);
功能:设置一个闹钟,当闹钟时间到达时,
向自己所在的进程发送一个SIGALRM的信号
参数:
seconds:设置的闹钟的定时时间
返回值:
成功返回上次设定剩余的时间
上次未设定则返回0
#include "head.h"void handler(int signum)
{printf("%d signal comming\n", signum);alarm(5);
}
int main(int argc, const char *argv[])
{signal(SIGALRM, handler);unsigned int cnt = alarm(5);while (1){printf("hello world\n");sleep(1);}return 0;
}
共享内存
共享内存:进程间效率做高的通信方式
1)通信原理
使用内核空间中的内存区域共享数据。
使用内存映射技术,减少的数据的反复拷贝,提高了通信效率。
共享内存操作流程
IPC对象
1)创建一个IPC key:
key_t ftok(const char *pathname, int proj_id);
2) 创建共享内存:
int shmget(key_t key, size_t size, int shmflg);
3) 建立共享内存段和用户空间的内存映射:
void *shmat(int shmid, const void *shmaddr, int shmflg);
4) 向共享内存写入数据--》通过用户空间的首地址
5)解除映射关系
int shmdt(const void *shmaddr);
6)删除共享内存
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
功能:创建一个IPC key
参数:
pathname:路径
proj_id: 工程ID
注意:两个进程在创建KEY时必须使用相同的参数
返回值:
成功:IPC key
失败:-1
int shmget(key_t key, size_t size, int shmflg);
功能:创建一个共享内存
参数:
key:IPC key
size:共享内存的大小
会被扩展成PAGE_SIZE(4096bytes)的整数倍
shmflg:
IPC_CREAT | 0664
返回值:
成功:共享内存的ID
失败:-1
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:建立共享内存内存映射
参数:
shmid :共享内存id
shmaddr:映射的用户空间首地址
NULL:让操作系统分配
shmflg:
SHM_RDONLY:只读
!SHM_RDONLY:可读可写
返回值:
成功:映射的用户空间首地址
失败:(void *) -1
int shmdt(const void *shmaddr);
功能:解除内存映射关系
参数:
shmaddr:要解除的用户空间首地址
返回值:
成功:0
失败:-1
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:操作共享内存
参数:
shmid:要操作的共享内存id
cmd:要执行的操作指令
IPC_RMID:删除操作
buf:设置的参数
返回值:
成功:0
失败:-1
ipcs -a 查看内核中的IPC对象
ipcrm -s 删除信号量集
ipcrm -m 删除共享内存
ipcrm -m shmid
ipcrm -M shmkey
6、信号量集
实现进程间同步
7、消息队列
和管道类似,有同步效果
增加数据的等级(优先级:优先级数据越小,优先级越高)
#include "head.h"int main(int argc, const char *argv[])
{//ftok();//shmget();//shmat();//p-->//shmdt();//shmctl();key_t key = ftok(".", '!');if (key < 0){perror("ftok error");return -1;}printf("key = %x\n", key);int shmid = shmget(key, 4096,IPC_CREAT|0664);if (shmid < 0){perror("shmget error");return -1;}printf("shmid = %d\n", shmid);void *pmem = shmat(shmid, NULL, !SHM_RDONLY);if ((void *)-1 == pmem){perror("shmat error");return -1;}//*((int *)pmem) = 10;strcpy((char *)pmem, "hello");shmdt(pmem);//shmctl(shmid, IPC_RMID, NULL);return 0;
}
#include "head.h"int main(int argc, const char *argv[])
{//ftok();//shmget();//shmat();//p-->//shmdt();//shmctl();key_t key = ftok(".", '!');if (key < 0){perror("ftok error");return -1;}printf("key = %x\n", key);int shmid = shmget(key, 4096, IPC_CREAT|0664);if (shmid < 0){perror("shmget error");return -1;}printf("shmid = %d\n", shmid);void *pmem = shmat(shmid, NULL, !SHM_RDONLY);if ((void *)-1 == pmem){perror("shmat error");return -1;}printf("recv: %s\n", (char *)pmem); shmdt(pmem);//shmctl(shmid, IPC_RMID, NULL);return 0;
}