进程和进程间通信
程序:存放在磁盘文件下的可执行文件
进程:是一个具有独立功能的程序对某个数据集合的一次运行活动。进程是程序的一个具体实现,进程是执行程序的过程。
实体结构:进程控制块(PCB),程序段,数据段
进程控制块:PCB是进程存在的唯一标识,是task_struct的结构体,task_struct==》结构体==》进程表项(进程控制块)
进程ID:每个进程只有一个ID,非负整数。
状态:有就绪,运行,挂起,停止。
并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。
如浏览器,听歌,qq等同时进行,该过程需要硬件手段时钟中断。
环境变量:一般是指在操作系统中用来指定操作系统运行环境的一些参数,以字符串“环境变量名=环境变量值”的形式存放的,用来描述进程环境信息
echo $PATH 查看环境变量 结果:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games 搜素路径由前到后
常用函数 #include<stdlib.h> getenv putenv setenv 应用时上网查看
fork函数:产生一个子进程
子进程的代码是父进程代码一个完全相同的拷贝
返回值有2个: 1、父进程返回子进程的pid (非负整数>0) 2、返回0 (子进程)
孤儿进程:父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为init进程,称为init进程领养孤儿进程。
僵尸进程:: 进程终止,父进程尚未回收,子进程残留资源(PCB)存放在内核中,变成僵尸(Zombie)进程
僵尸进程是不能使用kill命令清除掉的。 因为kill命令只是用来终止进程的,而僵尸进程已经终止
父子进程同步的功臣-------wait函数
进程间通信 (IPC,InterProcess Communication)
一、管道(使用最简单,进程间的大动脉)
- 进程通信必须经过内核
- 管道:管道是一个特殊的文件,是由队列实现的,是单向的,先进先出的,无结构的字节流。
- 管道实为内核使用环形队列机制,借助内核缓冲区(4K)实现。
- 无名管道(pipe):文件系统中无文件名(节点),不能用open文件创造,只能用pipe函数来创建管道
- 无名管道缺点:不能实现不是父子进程(血缘关系)之间的通信
- 有名管道(FIFO ) :文件系统中有文件名(节点)
- pipe函数
1 //函数形式: init pipe(int fd[2]) 2 //功能:创建管道,为系统调用 3 //头文件:unistd.h 4 //参数:得到的文件描述符。 fd[0]:读 出队 fd[1]:写 入队 5 //返回值:成功0,出错是-1
1 #include"stdio.h" 2 #include"unistd.h" 3 #include"stdlib.h" 4 int main() 5 { 6 int fd[2]; 7 int ret; 8 ret=pipe(fd); 9 if(ret<0) 10 { 11 printf("creat pipe failure\n"); 12 return -1; 13 } 14 printf("creat pipe sucess fd[0]=%d,fd[1]=%d\n",fd[0].fd[1]); n 15 return 0; 16 } 17
输出:creat pipe sucess fd[0]=3,fd[1]=4
注意:
- 管道是创建在内存中的,进程结束,空间释放,管道就不存在了
- 管道的东西读完了就删除
- 如果管道中没有东西读,则会阻塞
8、进程间通信
1 /* simplepipe.c 2 * parent read chars from stdin, then send them to child through pipe, 3 * child receive chars from pipe ,then display on stdout 4 */ 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <unistd.h> 8 #define BUFSIZE 1024 9 int main(void) { 10 int pid, fd[2], n; 11 char buf[BUFSIZE]; 12 if (pipe(fd) < 0) //pipe创建管道 13 { printf("pipe error\n"); exit(1); } 14 if ((pid = fork()) < 0) //创建子进程 15 { printf("fork failure\n"); exit(1); } 16 else if (pid == 0) { //child 17 close(fd[1]); 18 while((n = read(fd[0], buf, BUFSIZE))>0) { 19 write(STDOUT_FILENO, "receive from parent: ", 21); 20 write(STDOUT_FILENO, buf, n); 21 } 22 if (n < 0) 23 { printf("read error\n"); exit(1); } 24 close(fd[0]); 25 printf("exit child\n"); 26 exit(0); 27 } 28 close(fd[0]); 29 while((n=read(STDIN_FILENO, buf, BUFSIZE)) >0) 30 write(fd[1], buf, n); 31 if (n < 0) 32 { printf("read error\n"); exit(1); } 33 close(fd[1]); 34 printf("exit parent\n"); 35 return 0; 36 } 37 //退出程序:crtl+c
7. 有名管道:
通过有名管道,不相关的进程也能交换数据,所谓有名,即文件系统中存在这个一样的文件节点,每一个文件节点都有一个inode号而且这是一个特殊的文件类型:P管道类型
函数形式: int mkfifo(const char *pathname,mode_t mode) 功能:创建命名管道,没有在内核中创建管道,只有通过open函数打开打开这个文件时才会在内核空间创建管道 参数:路径 权限(与umask有关) 头文件:#include<sys/types.h> #include<sys/types.h> 返回:若成功为0,若出错则为-1
管道文件只有inode号,不占磁盘快空间,和套接字、字符设备文件、块设备文件一样。普通文件和符号链接文件及目录文件,不仅有inode号,还占磁盘块空间。
两个进程通信:
1 #include "stdio.h" 2 #include "unistd.h" 3 #include "stdlib.h" 4 #include "sys/types.h" 5 #include "sys/stat.h" 6 int main() 7 { 8 int ret; 9 ret=mkfifo("./myfifo",0777); 10 if(ret<0) 11 { 12 printf("creat myfifo failure\n"); 13 return -1; 14 } 15 printf("creat myfifo sucess\n"); 16 return 0; 17 }
1 //往管道写 2 #include "unistd.h" 3 #include "stdio.h" 4 #include "sys/types.h" 5 #include "stdlib.h" 6 #include "fcntl.h" 7 int main() 8 { 9 int fd; 10 int i; 11 char process_inter=0; 12 fd=open("./myfifo",O_WRONLY);//管道被创建 13 if(fd<0) 14 { 15 printf("open myfifo failure\n"); 16 return -1; 17 } 18 printf("open myfifo sucess\n"); 19 for(i=0;i<5;i++) 20 { 21 printf("this is first process i =%d\n",i); 22 usleep(100); 23 } 24 process_inter=1; 25 sleep(8); 26 write(fd,&process_inter,1);//往管道中写 27 while(1); 28 return 0; 29 }
1 //接收first从管道发的数据, 执行相关操作 2 //以上三个程序放在同一文件夹中,用两个中端查看结果 3 #include "unistd.h" 4 #include "stdio.h" 5 #include "sys/types.h" 6 #include "stdlib.h" 7 #include "fcntl.h" 8 int main() 9 { 10 int fd; 11 int i; 12 char process_inter=0; 13 fd=open("./myfifo",O_RDONLY); 14 if(fd<0) 15 { 16 printf("open myfifo failure\n"); 17 return -1; 18 } 19 printf("open myfifo sucess\n"); 20 read(fd,&process_inter,1); 21 while(process_inter==0); 22 for(i=0;i<5;i++) 23 { 24 printf("this is first process i =%d\n",i); 25 usleep(100); 26 } 27 while(1); 28 return 0; 29 }
二、信号(进程间的传令兵)
- kill l :查看信号 (一共64种信号)
- 信号是信息的载体,Linux/UNIX环境下,古老的、经典的通信方式。信号是软件中断。共性:简单。不能携带大量信息,满足某个特设条件下才发送。
- 信号的特质:由于信号是通过软件方法实现,其实现手段导致信号有很强的实延性。但对于用户来说,这个时延非常短,不易察觉
- 每个进程收到的所有信号都是由内核负责发送的,内核处理。
- 信号四要素:编号、名称、事件、默认处理动作
- 递达:递达并且到达进程
- 未决:产生和递达之间的状态。主要由于阻塞(屏蔽)导致该状态
- 信号的处理方式有:执行默认动作、忽略(丢弃),捕捉(用户处理函数)
- PCB包含信号相关的信息,主要是指阻塞信号集和未决信号集