企业不建立网站吗,百度收录,最好的在线网页代理,青岛西海岸新区建设局网站一、进程间通信常用方式
IPC方式#xff1a; Linux环境下#xff0c;进程地址空间相互独立#xff0c;每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到#xff0c;所以进程和进程之间不能相互访问#xff0c;要交换数据必须通过内核 Linux环境下进程地址空间相互独立每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到所以进程和进程之间不能相互访问要交换数据必须通过内核在内核中开辟一块缓冲区进程1把数据从用户空间拷到内核缓冲区进程2再从内核缓冲区把数据读走内核提供的这种机制称为进程间通信IPC,InterProcess Communication)。 在进程间完成数据传递需要借助操作系统提供特殊的方法如:文件、管道、信号、共享内存、消息队列、套接字、命名管道等。随着计算机的蓬勃发展一些方法由于自身设计缺陷被淘汰或者弃用。现今常用的进程间通信方式有: 1.管道使用最简单)
2.信号(开销最小)
3.共享映射区(无血缘关系)
4.本地套接字(最稳定) 二、管道
1.概念 管道是一种最基本的IPC机制作用于有血缘关系的进程之间完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质: 1.其本质是一个伪文件(实为内核缓冲区)
2.由两个文件描述符引用一个表示读端一个表示写端只能一次读取。
3.规定数据从管道的写端流入管道从读端流出单向流动。 管道的原理: 管道实为内核使用环形队列机制借助内核缓冲区(4k)实现。
管道的局限性: 1数据不能进程自己写自己读。· 2管道中数据不可反复读取。一旦读走管道中不再存在。 3采用半双工通信方式数据只能在单方向上流动。 4只能在有公共祖先的进程间使用管道
常用的通信方式 单工通信、半双工通信、全双工通信
创建管道文件
不占用磁盘空间 *2.pipe函数 函数功能创建并打开管道。 int pipe(int fd[2]); 参数 fd[0]: 读端。 fd[1]: 写端。 返回值 成功 0 失败 -1 errno
管道通信 #include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include errno.h
#include pthread.hvoid sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc, char *argv[])
{int ret,re;int fd[2];pid_t pid;char *str hello pipe\n;char buf[1024];ret pipe(fd);if(ret -1)sys_err(pipe error);pid fork();if(pid 0){ //父进程close(fd[0]); //关闭读段write(fd[1],str,strlen(str));//写入数据sleep(1);close(fd[1]); //关闭写段}else if(pid 0){ //子进程close(fd[1]); //关闭写段re read(fd[0],buf,sizeof(buf)); //读取数据write(STDOUT_FILENO,buf,re); //写到屏幕上close(fd[0]); //关闭读段}return 0;}*3.管道的读写行为 读管道 1. 管道有数据read返回实际读到的字节数。 2. 管道无数据 1无写端read返回0 类似读到文件尾 2有写端read阻塞等待。
写管道 1. 无读端 异常终止。 SIGPIPE导致的 2. 有读端 1 管道已满 阻塞等待 2 管道未满 返回写出的字节个数。 1读管道管道无数据无写端
#include stdio.h
#include stdlib.h
#include string.h
#include unistd.h
#include errno.h
#include pthread.hvoid sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc, char *argv[])
{int ret,re;int fd[2];pid_t pid;char *str hello pipe\n;char buf[1024];ret pipe(fd);if(ret -1)sys_err(pipe error);pid fork();if(pid 0){ //父进程close(fd[0]); //关闭读段// write(fd[1],str,strlen(str));//写入数据close(fd[1]); //关闭写段}else if(pid 0){ //子进程close(fd[1]); //关闭写段re read(fd[0],buf,sizeof(buf)); //读取数据printf(child read ret %d\n,ret);write(STDOUT_FILENO,buf,re); //写到屏幕上close(fd[0]); //关闭读段}return 0;}read返回0 4.父子间进程 使用管道实现父子进程间通信完成:ls | wc -l。假定父进程实现ls子进程实现wc
ls | wc -l命令 实现流程
1父进程创建管道 pipe()
2父进程创建子进程 fork()
3设置父进程执行ls命令子进程执行wc命令 execlp()
4设置父子进程通过管道的单项流动(设置指向标准输出的指向管道) dup2() #include stdio.h
#include stdlib.h
#include string.h
#include errno.h
#include unistd.h
#include pthread.hvoid sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc,char *argv[])
{/***************dup2();fork();pipe();execlp();****************/int fd[2]; int ret;pid_t pid;//父进程创建管道ret pipe(fd);if(ret -1){sys_err(pipe error);}//父进程创建子进程 pid fork();if(pid -1){sys_err(fork error);}else if(pid 0){close(fd[1]); //关闭写设置单项流动dup2(fd[0],STDIN_FILENO); //设置读管道信息execlp(wc,wc,-l,NULL); //设置子进程wc命令sys_err(execlp wc error);}else if(pid 0){close(fd[0]); //关闭读设置单项流动dup2(fd[1],STDOUT_FILENO); //设置写操作指向管道execlp(ls,ls,NULL); //设置父进程执行ls命令sys_err(execlp ls error);}return 0;
} 5.兄弟间进程通信
使用管道实现兄弟进程间通信完成:ls | wc -l。假定父进程实现ls子进程实现wc 实现流程
1父进程创建管道 pipe()
2父进程创建俩个兄弟子进程 fork()
3设置兄进程执行ls命令第进程执行wc命令 execlp()
4设置兄弟进程通过管道的单项流动(设置指向标准输出的指向管道) dup2()
5回收父进程残余文件 wait()
刚创建出的兄弟进程 设置兄弟进程通过管道的单项流动后 #include stdio.h
#include stdlib.h
#include string.h
#include errno.h
#include unistd.h
#include pthread.h
#include sys/wait.hvoid sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc,char *argv[])
{/***************dup2();fork();pipe();execlp();wait();****************/int fd[2]; int ret;int i;pid_t pid;//父进程创建管道ret pipe(fd);if(ret -1){sys_err(pipe error);}for(i 0;i 2;i){ //表达式2 出口仅限父进程使用pid fork();if(pid -1){sys_err(fork error);}if(pid 0) //子进程出口break;}if(i 2){ //父进程 //不需要父进程所以需要关闭他的读写并且回收掉父进程close(fd[0]); close(fd[1]);wait(NULL);wait(NULL);}else if(i 0){ //兄进程close(fd[0]);dup2(fd[1],STDOUT_FILENO);execlp(ls,ls,NULL); //兄进程执行ls命令sys_err(ececlp ls error);}else if(i 1){ //弟进程close(fd[1]);dup2(fd[0],STDIN_FILENO);execlp(wc,wc,-l,NULL);//弟进程执行wc命令sys_err(ececlp wc error);}return 0;
}6.多个读写端操作管道
实现一个pipe有一个写端多个读端
#include stdio.h
#include stdlib.h
#include string.h
#include errno.h
#include unistd.h
#include pthread.h
#include sys/wait.hvoid sys_err(const char *str)
{perror(str);exit(1);
}int main(int argc,char *argv[])
{/***************dup2();fork();pipe();execlp();****************/int fd[2],i,n; int ret;char buf[1024];pid_t pid;//父进程创建管道ret pipe(fd);if(ret -1){sys_err(pipe error);exit(1);}for(i 0;i 2;i){pid fork();if(pid -1){sys_err(fork error);exit(1);}if(pid 0)break;}if(i 2){ //父进程close(fd[1]); //父进程关闭写端留读端读取数据sleep(1);n read(fd[0],buf,1024); //从管道中读取数据write(STDOUT_FILENO,buf,n); for(i 0;i 2;i) //两个儿子wait两次wait(NULL);}else if(i 0){ //兄进程close(fd[0]);write(fd[1],1.hello\n,strlen(1.hello\n));}else if(i 1){ //弟进程close(fd[0]);write(fd[1],2.world\n,strlen(2.world\n));}return 0;
}7.管道缓冲区大小
可以使用 ulimIt -a 命令来查看当前系统中创建管道文件所对应的内核缓冲区大小。通常为: pipe size ......(512 bytes,-p) 8 也可以使用fpathconf函数借助参数―选项来查看。使用该宏应引入头文件unistd.h long fpathconf(int fd, int name);成功:返回管道的大小―失败:-1设置errno
.8.管道的优劣
优点:简单相比信号套接字实现进程间通信简单很多。
缺点: 1.只能单向通信双向通信需建立两个管道。 2.只能用父子、兄弟进程(有共同祖先)间通信。该问题后来使用fifo有名管道解决 三、FIFO:
fifo管道可以用于无血缘关系的进程间通信。 命名管道 mkfifo 无血缘关系进程间通信 读端open fifo O_RDONLY 写端open fifo O_WRONLY 1.命名管道fifo的创建和原理
使用命令myfifo myfifo 使用myfifo创建
#includestdio.h
#includesys/stat.h
#includeerrno.h
#includepthread.h
#includestdlib.hvoid sys_err(const char *str){perror(str);exit(1);
}int main(int argc,char *str)
{int ret mkfifo(mytestfifo,0664);if(ret -1)sys_err(mkfifo error);return 0;}