导图社区 进程间通信
这是一篇关于day5day6的思维导图,主要内容包括:消息队列:信息是带有类型的 可以过滤,IPC通信:共享内存 消息队列 信号灯集、ipcs命令 查看共享内存 消息队列 信号量、ipcs -s 查看信号量、ipcs -m 查看共享内存、ipcs -q 查看消息队列,共享内存,管道:在内核开辟的一块缓冲区,信号,进程间通信的方式。
编辑于2024-12-04 18:18:14这是一篇关于day5day6的思维导图,主要内容包括:消息队列:信息是带有类型的 可以过滤,IPC通信:共享内存 消息队列 信号灯集、ipcs命令 查看共享内存 消息队列 信号量、ipcs -s 查看信号量、ipcs -m 查看共享内存、ipcs -q 查看消息队列,共享内存,管道:在内核开辟的一块缓冲区,信号,进程间通信的方式。
这是一篇关于day4的思维导图,主要内容包括:设置线程属性,线程的同步,线程的互斥,线程。线程概念:为进一步减少处理器的空转时间,支持多处理器以及减少上下文切换开销,进程演化出线程,它是进程内独立的一条运行路线,是内核调度的最小单元。
这是一篇关于day3的思维导图,主要内容包括:守护进程,回收进程资源,孤儿进程和僵尸进程,exec族函数,结束进程,进程,Linux下的多任务机制。
社区模板帮助中心,点此进入>>
这是一篇关于day5day6的思维导图,主要内容包括:消息队列:信息是带有类型的 可以过滤,IPC通信:共享内存 消息队列 信号灯集、ipcs命令 查看共享内存 消息队列 信号量、ipcs -s 查看信号量、ipcs -m 查看共享内存、ipcs -q 查看消息队列,共享内存,管道:在内核开辟的一块缓冲区,信号,进程间通信的方式。
这是一篇关于day4的思维导图,主要内容包括:设置线程属性,线程的同步,线程的互斥,线程。线程概念:为进一步减少处理器的空转时间,支持多处理器以及减少上下文切换开销,进程演化出线程,它是进程内独立的一条运行路线,是内核调度的最小单元。
这是一篇关于day3的思维导图,主要内容包括:守护进程,回收进程资源,孤儿进程和僵尸进程,exec族函数,结束进程,进程,Linux下的多任务机制。
day5/day6
进程间通信的方式
1、管道
2、信号
3、消息队列
4、共享内存
5、信号量
6、socket套接字
其中12是传统通信方式 345是IPC通信方式 12345实现同一台主机间两个不同进间程通信 6实现 两台不同主机之间不同进程通信
管道:在内核开辟的一块缓冲区
无名管道:pipe函数 只能在亲缘关系之间进程通信
//pipe 管道 (1)头文件及函数原型 #include <unistd.h> int pipe(int pipefd[2]); //int pipe(int *pipefd); //调用 int pipefd[2] = { 0 };//用来保存读端和写端的文件描述符 //pipefd[0] 元素,里面保存的是读端的文件描述符 //pipefd[1] 元素,里面保存的是写端的文件描述符 pipe(pipefd); //将数组的首地址传递给pipe函数,得到无名管道读端和写端的文件描述符 read(pipefd[0], buf, sizeof(buf)); write(pipefd[1],buf, strlen(buf)); (2)功能: 创建一个无名管道 (3) 参数说明: int pipefd[2] //int * pipefd pipefd[0] //代表读端 pipefd[1] //代表写端 (4)返回值 成功: 0 失败:-1
功能:创建一个无名管道
返回值: 成功:0 失败:-1
无名管道特点总结: 1、无名管道只能作用于亲缘关系的进程中使用 2、无名管道是单工通信。有固定的读端和写端 fd[0]---读端的文件描述符,fd[1]---写端的文件描述符 3、无名管道是一个特殊的文件,不属于任何文件系统,只存在于内存中 4、无名管道中没有数据的时候,读取阻塞 5、无名管道写入的数据FIFO遵循先进先出规则 6、无名管道没有名字,在文件系统中不可见 调用pipe函数 得到读端和写端的文件描述符 7、无名管道不支持lseek移动文件指针
有名管道:fifo
1. 头文件及函数原型 #include <sys/types.h> #include <sys/stat.h> //mk make //fifo first in first out 先进先出 有名管道 int mkfifo(const char *pathname, mode_t mode); //调用 mkfifo("./myfifo", 0666); //相对路径方式 在当前目录下创建一个有名管道文件,名字叫myfifo mkfifo("/home/linux/Public/myfifo",0666); //绝对路径方式 在Public下创建 创建一个有名管道文件,名字叫myfifo 2. 功能: 创建一个有名管道 3. 参数说明: const char *pathname //创建有名管道文件的名字(可以有相对路径或绝对路径的修饰) mode_t mode //管道文件的访问权限 0666 4. 返回值 成功: 0 失败: -1
创建有名管道:mkfifo函数
功能:创建一个有名管道
返回值: 成功:0 失败:-1
当有名管道读端存在的时候 往管道中写入数据才有意义 先运行读端
有名管道特点总结: 1、有名管道可以在亲缘进程和非亲缘进程间都可以使用 2、有名管道是单工通信,有固定的读端和写端 3、有名管道不属于任何一个文件系统 只存在于内存中 4、有名管道中无数据的时候 读取阻塞 5、有名管道写入的时候 FIFO 遵循先进先出规则 6、有名管道有名字 在文件系统中可见,可以调用open 函数打开管道 通过文件描述符进程read write 7、有名管道不支持1seek移动文件指针
信号
关于信号
信号:唯一的异步通信机制 同步:事件按照一定的顺序执行 异步:事件什么时候来不知道
信号的使用:一个进程发生给另一个进程
信号发出者:进程 内核
信号接收者:进程
关于CTRL+c 摁下ctrl+c终端识别后 内核发出了一个信号给当前正在运行的进程 告诉进程立刻停止运行
如何查看系统有那些信号: kill -l
#define SIGINT 2 #define SIGQUIT 3 SIGINT ctrl+c //2 SIGQUIT ctrl+\ 终止程序 //3 SIGILL 非法指令 SIGABRT 通过abort函数实现程序终止,abort函数为异常终止一个进程 SIGFPE 除数为0 会产生 --浮点异常 SIGKILL 必杀信号 // 9 SIGSEGV 段错误--地址非法使用 SIGPIPE 管道破裂 SIGALRM 闹钟信号 用alarm函数设置闹钟 告诉系统时间到 当时间到 就会发送这个信号 //14 SIGTERM 终止信号 kill命令向进程发送这个信号 //15 kill 6785 SIGCHLD 子进程终止 或者停止的时候 会向父进程发送此信号 //17 SIGCONT 让一个暂停的进程继续 SIGSTOP 让一个程序暂停 SIGTSTP ctrl+z 将前台进程扔到后台 并使该进程处于暂停状态 //20
信号的响应方式 当一个进程收到一个信号以后 会有三种响应这个信号的方式
(1)执行默认操作(缺省操作) //每一个信号都有自己默认的处理方式
(2)忽略信号://发了跟没发一样,当没看见
(3)捕捉信号://去执行另一个事情
接收信号:signal函数
(1) 函数原型 void (*signal(int signum, void (*handler)(int)))(int); 函数名字叫什么?? signal//功能 接收信号 有三种响应方式 函数的参数有哪些?? //参数列表:离函数名最近的()里面的就是参数列表 (int signum, void (*handler)(int)) int signum, void (*handler)(int) 函数的返回值类型是什么?? //返回值:把名字和参数列表挡住 就是返回值 void(*)(int) //指针类型重定义 typedef int *p_t;//将int* 类型重定义为 p_t typedef void(*handler_t)(int);//将void(*)(int)类型重定义为handler_t handler_t signal(int signum,handler_t handler); (2)功能: 实现对接收到的信号的三种响应方式 (3)参数: typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler); int signum //接收的信号编号 void (*handler)(int) //函数指针,接收到信号后的响应方式 //调用 //1. 忽略响应方式 signal(SIGINT, SIG_IGN);// ignore SIG_IGN 忽略信号的方式,响应信号 //2. 执行默认操作响应方式 signal(SIGINT, SIG_DFL);// default SIG_DFL 执行默认操作的方式,响应信号 //3. 捕捉信号后,去做的那件事,执行fun函数 void fun(int num) { } signal(SIGINT, fun);// 捕捉信号方式,响应信号,fun函数,是自定义函数 (4)返回值 返回值是一个函数指针 void (*)(int)
功能:接收信号
返回值:是一个函数指针 void(*)(int)
有两个信号,无法捕捉也无法忽略,SIGKILL(9)和SIGSTOP(19),这两个信号级别很高,是留给操作系统管理和调试进程用的,用来终止进程和暂停进程,任何用户进程收到这两个信号,必须停止或者暂停
发送信号:
kill函数
(1)头文件及函数原型 #include <sys/types.h> #include <signal.h> int kill(pid_t pid, int sig); //调用 kill(3111,SIGINT); //给PID是3111的进程,发送一个SIGINT信号 kill(2365,SIGQUIT); //给PID是2365的进程,发送一个SIGQUT信号 (2)功能: 使用kill函数,可以给指定某个进程,发送任意一个信号 (3)参数说明: pid_t pid //接收信号进程的PID int sig //给指定进程发送的信号编号
功能:使用kill函数,可以给指定某个进程,发送任意一个信号
返回值: 成功:0 失败:-1
raise函数
(1)头文件及函数原型 #include <sys/types.h> #include <signal.h> int raise(int sig); //调用 raise(SIGINT); //给当前进程自己,发送一个SIGINT信号 raise(SIGQUIT); //给当前进程自己,发送一个SIGQUT信号 (2)功能: 使用raise函数,可以当前进程自己发送任意一个信号 (3)参数说明: int sig //给当前进程自己发送的信号编号 (4)返回值: 成功: 0 失败: -1
功能:使用raise函数,可以当前进程自己发送任意一个信号
返回值: 成功:0 失败:-1
alarm函数
(1) 函数原型 unsigned int alarm(unsigned int seconds) (2)功能:能定期产生信号 称为闹钟函数,它可以在进程中设置一个定时器,当定时器时间到,内核 向进程发送SIGALRM信号 信号编号14 (3) 参数: unsigned int seconds //秒数,每隔多久产生一次信号 alarm(1); //1s之后自动产生一个SIGALRM信号 alarm(4); //4s之后自动产生一个SIGALRM信号 alarm(10); sleep(3); alarm(5); (4) 返回值: 成功: 如果调用此alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟时间的剩余时间,否则返回0。 失败: -1
功能:能定期产生信号 称为闹钟函数,它可以在进程中设置一个定时器,当定时器时间到,内核向进程发送SIGALRM信号
返回值: 成功: 如果调用此alarm()前,进程中已经设置了闹钟时间, 则返回上一个闹钟时间的剩余时间,否则返回0。 失败:-1
SIGCHLD信号
#define SIGCHLD 17 CHLD --> child缩写 SIGCHLD信号什么时候产生??? 当子进程结束的时候,内核会给父进程发送一个SIGCHLD信号,父进程的默认操作是 忽略此信号 子进程的结束,是SIGCHLD信号杀死的吗?? 不是 我们利用SIGCHLD信号可以避免出现僵尸进程
消息队列:信息是带有类型的 可以过滤
什么是消息队列:可以发送和接收多个消息,这些消息在内核中一个队列里面缓存着(如果没有人取走就一直停留在那里)
消息队列特点: 1、消息是先进先出的,当不过滤类型时,先发的消息会被先读取 2、消息可以按类型过滤,也可以不过滤 3、消息是一个整体 有 类型+正文 可以是个结构体 结构体可以根据需求自己定义 struct msgbuf { long mtype;//消息类型 char mtext[100];//消息正文 };
查看和删除消息队列
ipcs -q //查看消息队列
ipcs -q id//删除这个id的消息队列
如何使用消息队列
1、创建消息队列msgget()
(1)头文件及函数原型 #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgget(key_t key, int msgflg); (2)功能:创建消息队列 (3)参数: key_t key //和共享内存相关的key值理解相同,通过同一个key来获取同一消息队列的ID int msgflg //消息队列的访问权限 0666 //调用参考 int msgid = msgget(IPC_PRIVATE, 0666); //亲缘进程 int msgid = msgget(44444, IPC_CREAT | 0666); //不相关的进程 (4)返回值: 成功:消息队列ID 唯一标识这个消息队列 失败:-1
功能:创建消息队列
返回值: 成功:消息队列ID, 唯一标识这个消息队列 失败:-1
2、写入消息队列msgsnd()
(1)头文件及函数原型 #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); struct msgbuf { long mtype; //表示消息的类型 char mtext[100]; //消息的正文 }; (2)功能: 发送消息 (3)参数: int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); struct msgbuf { long mtype; //表示消息的类型 char mtext[100]; //消息的正文 }; int msqid:消息队列的ID,msgget返回值 const void *msgp: 要发送的消息的首地址 (存放的位置) struct msgbuf { long mtype; //表示消息的类型 char mtext[100]; //消息的正文 }; size_t msgsz 消息正文的字节数 int msgflg 发送方式选项 0 阻塞(如果消息队列满,再继续发送消息,会阻塞) IPC_NOWAIT 不阻塞 //调用参考 struct msgbuf a = {2,"hello"}; //消息类型是2, 消息正文是 "hello" msgsnd(msgid, &a, sizeof(a) - sizeof(long), 0); (4)返回值: 成功 0 失败 -1 (5)实例: struct msgbuf a = {2,"hello"}; msgsnd(msgid, &a, sizeof(a) - sizeof(long), 0);
功能:发送消息
返回值: 成功:0 失败:-1
3、读取消息队列msgrcv()
(1)头文件及函数原型 #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg); (2)功能:接收消息 (3)参数 int msqid: msgget的返回值,消息队列的ID void *msgp: 要接收的消息存放的位置(接收消息的缓存区) , 发送和接收结构体要对应 struct mtype { long mtype; //表示消息的类型 char mtext[100]; //消息的正文 }; size_t msgsz: 消息正文的字节数 long msgtyp 0 接收消息队列中第一个消息,不过滤消息 >0 接收消息队列中类型值为msgtyp的消息,过滤消息 struct msgbuf b = { 0 }; msgrcv(msgid, &b, sizeof(b)-sizeof(long),0,0); //接收消息队列中第一个消息,不过滤 msgrcv(msgid, &b, sizeof(b)-sizeof(long),3,0);//只接收消息队列中类型为3的消息 msgrcv(msgid, &b, sizeof(b)-sizeof(long),500,0);//只接收消息队列中类型为500的消息 int msgflg 接收方式选项 0 阻塞(如果消息队列空,会阻塞等待) IPC_NOWAIT 不阻塞 //调用参考 struct msgbuf b = { 0 }; msgrcv(msgid, &b, sizeof(b) - sizeof(long),15, 0); (4)返回值: >0 接收的消息的长度 -1 出错
功能:接收消息
返回值: 成功:>0 接收的消息长度 失败:-1
4、删除消息队列msgctl()
(1)头文件及函数原型 #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> int msgctl(int msqid, int cmd, struct msqid_ds *buf); //调用 msgctl(msgid, IPC_RMID, NULL); (2) 功能: 删除消息队列 (3) 参数: int msqid: //msgget的返回值,消息队列的ID int cmd: IPC_STAT //读取消息队列的属性,并将其保存在buf指向的缓存区中 IPC_SET //设置消息队列的属性,这个值取自buf参数 IPC_RMID //从系统中删除消息队列。 struct msqid_ds *buf: //设置或者获取属性使用第三个参数 //调用参考 msgctl(msgid, IPC_RMID, NULL); (4) 返回值: 成功: 0 失败: -1
功能:删除消息队列
返回值: 成功:0 失败:-1
共享内存
什么是共享内存:在内核空间提供一块内存区,多个进程可以共享访问,对这块内存进行直接读写
共享内存特点:共享内存是进程通信机制中效率最高的 采用的是映射机制:将内存地址映射到各自的进程的物理地址空间
使用共享内存注意问题: 注意多进程或者多线程的互斥和同步
如何使用共享内存: 1、创建共享内存(shmget()) 2、映射共享内存(shmat()) 3、对共享内存进行读或者写 4、解除共享内存映射(shmdt()) 5、删除共享内存(shmctl())
创建共享内存:shmget函数
(1)头文件及函数原型 #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int shmget(key_t key, int size, int shmflg); (2)功能: 创建一个共享内存 (3)参数: #define IPC_PRIVATE 0 key 创建共享内存时的内存key值,如果值为 IPC_PRIVATE, 表示此共享内存是私有的, 只能在亲缘关系进程之间使用,非0值表示,创建一个指定ID的共享内存 多个进程可以通过同一个key值得到同一共享内存的ID key值是几不重要,重要的是多进程在创建共享内存的时候,用同一个key值,这样就可以 得到同一块共享内存的ID size 创建的共享内存的大小,以字节为单位 shmflg 创建共享内存的访问权限 0666 //调用参考 //有亲缘关系进程间使用 key值用 IPC_PRIVATE //#define IPC_PRIVATE 0 int shmid = shmget(IPC_PRIVATE, sizeof(int), 0666); //无亲缘关系进程间使用 key值用 非0的值,指定一个key值 int shmid = shmget(55555, sizeof(int), IPC_CREAT | 0666); (4)返回值: 成功:是共享内存的id, 能唯一识别一块共享内存 失败:-1
功能:创建一个共享内存
返回值: 成功:共享内存的ID 唯一能够识别共享内存的标识 失败:-1
映射共享内存:shmat函数
//映射共享内存,就是为了得到共享内存的首地址 (1)头文件及函数原型 #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> void *shmat(int shmid, const void *shmaddr, int shmflg); (2)功能:将共享内存映射到进程自己的内存空间,得到首地址 (3)参数: 1)shmid 是shmget的返回值 2)shmaddr 如果非NULL值,表示将共享内存映射到指定地址, 通常写NULL 3)shmflg 通常是 0, 表示共享内存可读可写,也可以写成SHM_RDONLY 只读 //调用参考 int shmid = shmget(55555, sizeof(int), IPC_CREAT | 0666);//创建 int *p = shmat(shmid, NULL, 0);//映射 (4)返回值: 映射到进程的有效地址,通过此地址,可以访问共享内存
功能:将共享内存映射到进程自己的内存空间,得到首地址
返回值:映射到进程的有效地址,通过地址访问共享内存
读写共享内存 a.向共享内存写入内容 *p = 200; b.将共享内存中的内容直接读取打印 printf("*p is %d\n",*p); c. 将共享内存中的内容拷贝出来再打印 int num = *p; printf("num is %d\n",num);
a.向共享内存写入内容 *p = 200; b.将共享内存中的内容直接读取打印 printf("*p is %d\n",*p); c. 将共享内存中的内容拷贝出来再打印 int num = *p; printf("num is %d\n",num);
解除共享内存映射:shmdt函数
(1)头文件及函数原型 #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int shmdt(const void *shmaddr); (2)功能:解除共享内存映射 (3)参数: shmaddr 共享内存映射后的地址 //调用参考 shmdt(p); //解除共享内存映射 (4)返回值: 成功 0 失败 -1
功能:解除共享内存映射
返回值: 成功:0 失败:-1
删除共享内存shmctl函数
(1)头文件及函数原型 #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> int shmctl(int shmid, int cmd, struct shmid_ds *buf); (2)功能:删除共享内存 或者 设置共享属性 或者 获取共享内存属性 (3)参数: int shmid: 要操作的共享内存标识符 int cmd: 选择shmctl函数的功能 IPC_STAT(获取对象属性) struct shmid_ds s = { 0 }; //s用来保存共享内存属性的结构体 shmctl(shmid, IPC_STAT, &s);//参数地址传递的方式获取共享内存属性 IPC_SET (设置对象属性) struct shmid_ds s;//里面装上要设置的属性 //修改结构体变量s中存储的内容,即要设置的属性 shmctl(shmid, IPC_SET, &s); IPC_RMID (删除对象) buf : 指定IPC_STAT/IPC_SET时用以保存/设置属性 //调用参考 shmctl(shmid, IPC_RMID, NULL);//删除共享内存 (4)返回值: 成功 0 失败 -1
功能:删除共享内存 或者 设置共享属性 或者 获取共享内存属性
返回值: 成功:0 失败:-1
IPC通信:共享内存 消息队列 信号灯集 ipcs命令 查看共享内存 消息队列 信号量 ipcs -s 查看信号量 ipcs -m 查看共享内存 ipcs -q 查看消息队列
# 通信第一天:传统通信 # 通信第二天:IPC