IO进程线程day8(2023.8.6)

一、Xmind整理:

管道的原理:

有名管道的特点: 

信号的原理:

二、课上练习:

练习1:pipe

功能:创建一个无名管道,同时打开无名管道的读写端

原型:

#include <unistd.h>
int pipe(int pipefd[2]); int* pfd;  int pfd[]

参数:

int pipefd[2]:函数运行完毕后,该参数指向的数组中会存储两个文件描述符;
pipefd[0]:    读端文件描述符;
pipefd[1]:    写端文件描述符;

返回值:

成功,返回0;
失败,返回-1,更新errno;

小练: 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
int main(int argc, const char *argv[])
{//管道的创建必须放在fork函数前//若放在fork函数后,会导致父子进程各自创建一根管道//此时会导致父子进程各自操作各自的管道,无法进行通信int pfd[2] = {0};if(pipe(pfd) < 0){perror("pfd");return -1;}printf("pipe success pfd[0]=%d pfd[1]=%d\n",pfd[0],pfd[1]);pid_t cpid = fork();if(cpid > 0)  //父进程中为真{//父进程发送数据给子进程char buf[128]="";while(1){fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1] = 0;     //从终端获取数据,最后会拿到\n字符,将\n字符修改成0//将数据写入到管道文件中if(write(pfd[1],buf,sizeof(buf)) < 0){perror("write");return -1;}printf("写入成功\n");}}else if(0 == cpid)      //子进程中为真{//子进程读取父进程发送过来的数据char buf[128] = "";ssize_t res = 0;while(1){bzero(buf,sizeof(buf));printf("__%d__\n",__LINE__);//当管道中没有数据的时候,read函数阻塞res = read(pfd[0],buf,sizeof(buf));printf("res=%ld : %s\n",res,buf);                                                         }}else{perror("fork");return -1;}return 0;
}

练习2:mkfifo

功能:创建一根有名管道

原型:

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);

参数:

char *pathname:指定要创建的有名管道的路径以及名字;
mode_t mode:有名管道的权限:0664 0777,真实的权限 (mode & ~umask)
the  permissions of the created file are (mode & ~umask)

返回值:

成功,返回0;
失败,返回-1,更新errno;
errno == 17,文件已经存在的错误,这是一个允许存在的错误,忽略该错误

练习3:操作有名管道

功能:操作有名管道与用文件IO操作普通文件一致

原型:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);

参数:

  int flags:O_RDONLY  只读O_WRONLY  只写O_RDWR    读写---上述三种必须,且只能包含一种---O_NONBLOCK     非阻塞

1.int flags == O_RDONLY

    open函数阻塞,此时需要另外一个进程或线程以写的方式打开同一根管道,open函数解除阻塞

2.int flags == O_WRONLY

   open函数阻塞,此时需要另外一个进程或线程以读的方式打开同一根管道,open函数解除阻塞

3.int flags == O_RDWR

   open函数不阻塞,此时管道的读写端均被打开

   当管道的读写端均被打开的时候,此时open函数不阻塞

4.int flags == O_RDONLY | O_NONBLOCK

   open函数不阻塞,open函数运行成功,此时管道只有读端

5.int flags == O_WRONLY | O_NONBLOCK

   open函数不阻塞,open函数运行失败,此时管道的读写端均打开失败 

示例: 

读端:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>int main(int argc, const char *argv[])
{umask(0);if(mkfifo("./fifo", 0777) < 0){//printf("errno = %d\n", errno);if(errno != 17)     //17 == EEXIST{perror("mkfifo");return -1;}}printf("create FIFO success\n");//open函数阻塞int fd = open("./fifo", O_RDONLY);if(fd < 0){perror("open");return -1;}printf("open FIFO rdonly success  fd=%d\n", fd);char buf[128] = "";ssize_t res = 0;while(1){bzero(buf, sizeof(buf));res = read(fd, buf, sizeof(buf));if(res < 0){perror("read");return -1;                                  }else if(0 == res){printf("对端关闭\n");break;}printf("%ld :%s\n", res, buf);}close(fd);return 0;
}

写端:

#include <stdio.h>                                    
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>int main(int argc, const char *argv[])
{umask(0);if(mkfifo("./fifo", 0777) < 0){   //printf("errno = %d\n", errno);if(errno != 17)     //17 == EEXIST{perror("mkfifo");return -1; }}   printf("create FIFO success\n");//open函数阻塞int fd = open("./fifo", O_WRONLY);if(fd < 0){   perror("open");return -1; }   printf("open FIFO wronly success  fd=%d\n", fd);char buf[128] = ""; while(1){   printf("请输入>>>");fgets(buf, sizeof(buf), stdin);buf[strlen(buf)-1] = 0;if(write(fd, buf, sizeof(buf)) < 0){perror("write");return -1; }printf("写入成功\n");}   close(fd);return 0;
}

小练:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>                                                                         
int main(int argc, const char *argv[])
{//创建有名管道if(mkfifo("./fifo",0664) < 0){//printf("%d\n",errno);if(errno != 17)    //17:文件已经存在错误,这是一个允许存在的错误,忽略该错误{perror("mkfifo");return -1;}}printf("mkfifo success\n");/*int fd = open("./fifo",O_RDWR);if(fd <  0){perror("open");return -1;}printf("open success fd = %d\n",fd);
*/int fd_r = open("./fifo",O_RDONLY|O_NONBLOCK);if(fd_r <  0){perror("open");return -1;}printf("open success fd_r = %d\n",fd_r);int fd_w = open("./fifo",O_WRONLY|O_NONBLOCK);if(fd_w <  0){perror("open");return -1;}printf("open success fd_w = %d\n",fd_w);return 0;
}

练习4:常见的信号

练习5:signal

功能:捕获信号,为信号注册新的处理函数

原型:

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);     //void (*handler)(int);

参数:

int signum:指定要捕获的信号对应的编号。可以填编号,也可以填对应的宏。2) SIGINT
sighandler_t handler:函数指针,回调函数;
1) SIG_IGN:忽略信号;     9) 19)号信号无法忽略;
2) SIG_DFL:执行默认操作;
3) 传入一个函数的首地址,代表捕获信号,且该函数的返回值必须是void类型,参数列表必须是int类型,例如:void handler(int sig){                                    }
typedef void (*sighandler_t)(int);     typedef void (*)(int)   sighandler_t; 
typedef 旧的类型名  新的类型名;
typedef int uint32_t;                  int a ----> uint32_t a;
typedef int*    pint;                  int* pa ---> pint pa;
typedef void (*)(int)   sighandler_t;  void (*ptr)(int) ----> sighandler_t ptr;

返回值:

成功,返回该信号的上一个信号处理函数的首地址; 默认处理函数的首地址获取不到,返回NULL;
失败,返回SIG_ERR ((__sighandler_t)-1),更新errno;      

小练: 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <head.h>
void handler(int sig)
{printf("this is sig=%d\n",sig);return;
}
int main(int argc, const char *argv[])
{//捕获2号SIGINT信号if(signal(2,handler) == SIG_ERR){perror("signal");return -1;}printf("捕获2号信号成功\n");//捕获3号SIGINT信号if(signal(3,handler) == SIG_ERR){perror("signal");return -1;}printf("捕获3号信号成功\n");//捕获20号SIGINT信号if(signal(20,handler) == SIG_ERR){perror("signal");return -1;}printf("捕获20号信号成功\n");while(1){printf("this is main func\n");sleep(1);}return 0;
}

三、课后作业:

1.要求实现AB进程对话

   A进程先发送一句话给B进程,B进程接收后打印

   B进程再回复一句话给A进程,A进程接收后打印

   重复1.2步骤,当收到quit后,要结束AB进程

   提示:两根管道

A进程: 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>                                                                                       
int main(int argc, const char *argv[])
{//创建有名管道if(mkfifo("./fifo",0664) < 0){//printf("%d\n",errno);if(errno != 17)    //17:文件已经存在错误,这是一个允许存在的错误,忽略该错误{perror("mkfifo");return -1;}}printf("mkfifo success\n");if(mkfifo("./fifo1",0664) < 0){//printf("%d\n",errno);if(errno != 17)    //17:文件已经存在错误,这是一个允许存在的错误,忽略该错误{perror("mkfifo");return -1;}}printf("mkfifo1 success\n");int fd_r= open("./fifo",O_RDONLY);if(fd_r <  0){perror("open");return -1;}printf("open success fd_r = %d\n",fd_r);int fd_w = open("./fifo1",O_WRONLY);if(fd_w <  0){perror("open");return -1;}printf("open success fd_w= %d\n",fd_w);//从管道中读取数据,打印到终端上char buf[128]="";ssize_t res = 0;while(1){bzero(buf,sizeof(buf));//当管道的读写端均存在,若管道中没有数据,则read函数阻塞res = read(fd_r,buf,sizeof(buf));if(strcmp(buf,"quit") == 0){write(fd_w,buf,sizeof(buf));break;}if(res < 0){perror("read");return -1;}if(0 == res){printf("写端关闭\n");break;}printf("res =%ld\n输出:%s\n",res,buf);bzero(buf, sizeof(buf));printf("请输入:");fgets(buf, sizeof(buf),stdin);buf[strlen(buf)-1] = '\0';if(write(fd_w,buf,sizeof(buf))< 0){perror("write");return -1;}printf("写入数据成功  res =%ld\n",res);}close(fd_r);close(fd_w);return 0;
}

B进程:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <head.h>
int main(int argc, const char *argv[])
{//创建有名管道if(mkfifo("./fifo",0664) < 0){//printf("%d\n",errno);if(errno != 17)    //17:文件已经存在错误,这是一个允许存在的错误,忽略该错误{perror("mkfifo");return -1;}}printf("mkfifo success\n");if(mkfifo("./fifo1",0664) < 0){//printf("%d\n",errno);if(errno != 17)    //17:文件已经存在错误,这是一个允许存在的错误,忽略该错误{perror("mkfifo");return -1;}}printf("mkfifo1 success\n");int fd_w = open("./fifo",O_WRONLY);if(fd_w <  0){perror("open");return -1;}printf("open success fd_w= %d\n",fd_w);int fd_r= open("./fifo1",O_RDONLY);                                                                                                       if(fd_r <  0){perror("open");return -1;}printf("open success fd_r = %d\n",fd_r);//从终端获取数据,写到管道中char buf[128]="";ssize_t res = 0;while(1){bzero(buf, sizeof(buf));printf("请输入:");fgets(buf,sizeof(buf),stdin);buf[strlen(buf)-1] = '\0';if(strcmp(buf,"quit") == 0){write(fd_w,buf,sizeof(buf));break;}if(write(fd_w,buf,sizeof(buf)) < 0){perror("write");return -1;}printf("写入数据成功  res =%ld\n",res);bzero(buf,sizeof(buf));//当管道的读写端均存在,若管道中没有数据,则read函数阻塞res = read(fd_r,buf,sizeof(buf));if(res < 0){perror("read");return -1;}if(0 == res){printf("写端关闭\n");break;}printf("res =%ld\n输出:%s\n",res,buf);}close(fd_w);close(fd_r);return 0;
}

2.在第1题的基础上实现,A能随时发信息给B,B能随时接收A发送的数据,反之亦然。

A进程:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <signal.h>int main(int argc, const char *argv[])
{if(mkfifo("./fifo", 0775) < 0) 	 	//当前进程写该管道{if(17 != errno) 	//#define EEXIST      17{perror("mkfifo");return -1;}}printf("fifo create success\n");if(mkfifo("./fifo1", 0775) < 0)     //当前进程读该管道{if(17 != errno)     //#define EEXIST      17{perror("mkfifo");return -1;}}printf("fifo1 create success\n");//创建一个子进程pid_t cpid = fork();if(cpid > 0){//读  fifo1int fd_r = open("./fifo1", O_RDONLY);    //阻塞if(fd_r < 0){perror("open");return -1;}printf("open fifo rdonly success __%d__\n", __LINE__);ssize_t res = 0;char buf[128] = "";while(1){bzero(buf, sizeof(buf));//读写段均存在,且管道中没有数据,该函数阻塞res = read(fd_r, buf, sizeof(buf));if(res < 0){perror("read");return -1;}else if(0 == res){printf("对端进程退出\n");break;                                      }printf("res=%ld : buf=%s\n", res, buf);if(!strcmp(buf, "quit"))break;}close(fd_r);kill(cpid, 9);wait(NULL);}else if(0 == cpid){//写 fifoint fd_w = open("./fifo", O_WRONLY);  //阻塞if(fd_w < 0){perror("open");return -1;}printf("open fifo wronly success __%d__\n", __LINE__);char buf[128] = "";while(1){bzero(buf, sizeof(buf));//	printf("请输入>>>");fgets(buf, sizeof(buf), stdin);buf[strlen(buf)-1] = 0;if(write(fd_w, buf, sizeof(buf)) < 0){perror("write");return -1;}//	printf("写入成功\n");if(!strcmp(buf, "quit"))break;}close(fd_w);kill(getppid() , 9);}else{perror("fork");return -1;}return 0;
}

B进程:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/wait.h>
#include <signal.h>int main(int argc, const char *argv[])
{if(mkfifo("./fifo", 0775) < 0) 	 	//当前进程写该管道{if(17 != errno) 	//#define EEXIST      17{perror("mkfifo");return -1;}}printf("fifo create success\n");if(mkfifo("./fifo1", 0775) < 0)     //当前进程读该管道{if(17 != errno)     //#define EEXIST      17{perror("mkfifo");return -1;}}printf("fifo1 create success\n");//创建一个子进程pid_t cpid = fork();if(cpid > 0){//读  fifoint fd_r = open("./fifo", O_RDONLY);    //阻塞if(fd_r < 0){perror("open");return -1;}printf("open fifo rdonly success __%d__\n", __LINE__);ssize_t res = 0;char buf[128] = "";while(1){bzero(buf, sizeof(buf));//读写段均存在,且管道中没有数据,该函数阻塞res = read(fd_r, buf, sizeof(buf));if(res < 0){perror("read");return -1;}else if(0 == res){printf("对端进程退出\n");break;                                      }printf("res=%ld : buf=%s\n", res, buf);if(!strcmp(buf, "quit"))break;}close(fd_r);kill(cpid, 9);wait(NULL);}else if(0 == cpid){//写 fifo1int fd_w = open("./fifo1", O_WRONLY);  //阻塞if(fd_w < 0){perror("open");return -1;}printf("open fifo wronly success __%d__\n", __LINE__);char buf[128] = "";while(1){bzero(buf, sizeof(buf));//printf("请输入>>>");fgets(buf, sizeof(buf), stdin);buf[strlen(buf)-1] = 0;if(write(fd_w, buf, sizeof(buf)) < 0){perror("write");return -1;}//	printf("写入成功\n");if(!strcmp(buf, "quit"))break;}close(fd_w);kill(getppid() , 9);}else{perror("fork");return -1;}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/55648.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Stable Diffusion系列课程二:ControlNet

AUTOMATIC1111/stable-diffusion-webui参考B站Nenly视频《零基础学会Stable Diffusion》、视频课件推荐网站&#xff1a;stable-diffusion-art、Civitai&#xff08;魔法&#xff09; 、libilibi、AI艺术天堂推荐Stable Diffusion整合资料&#xff1a; NovelAI资源整合、《AI绘…

18 | 基于DDD的微服务设计实例

为了更好地理解 DDD 的设计流程&#xff0c;这篇文章会用一个项目来带你了解 DDD 的战略设计和战术设计&#xff0c;走一遍从领域建模到微服务设计的全过程&#xff0c;一起掌握 DDD 的主要设计流程和关键点。 项目基本信息 项目的目标是实现在线请假和考勤管理。功能描述如下…

移动开发最佳实践:为 Android 和 iOS 构建成功应用的策略

您可以将本文作为指南&#xff0c;确保您的应用程序符合可行的最重要标准。请注意&#xff0c;这份清单远非详尽无遗&#xff1b;您可以加以利用&#xff0c;并添加一些自己的见解。 了解您的目标受众 要制作一个成功的应用程序&#xff0c;你需要了解你是为谁制作的。从创建…

【N32L40X】学习笔记14-在RT-thread系统中读取eeprom数据

eeprom 说明 eeprom介绍 AT24C01A&#xff0c;1K串行EEPROM&#xff1a;内部组织16页8字节&#xff0c;1K需要一个7位数据字地址进行随机字寻址。AT24C02,2K串行EEPROM&#xff1a;内部组织32页8字节&#xff0c;2K需要一个8位数据字地址进行随机字寻址。AT24C04,4K串行EEPRO…

svn工具使用

svn 介绍 解决之道&#xff1a; SCM&#xff1a;软件配置管理 所谓的软件配置管理实际就是对软件源代码进行控制与管理 CVS&#xff1a;元老级产品 VSS&#xff1a;入门级产品 ClearCase&#xff1a;IBM 公司提供技术支持 SVN&#xff1a;主流产品 什么是SVN&#xff…

使用gitee创建远程maven仓库

1. 创建一个项目作为远程仓库 2. 打包项目发布到远程仓库 id随意&#xff0c;url是打包到哪个文件夹里面 在需要打包的项目的pom中添加 <distributionManagement><repository><id>handsomehuang-maven</id><url>file:D:/workspace/java/2023/re…

[openCV]基于拟合中线的智能车巡线方案V1

import cv2 as cv import os import numpy as np# 遍历文件夹函数 def getFileList(dir, Filelist, extNone):"""获取文件夹及其子文件夹中文件列表输入 dir&#xff1a;文件夹根目录输入 ext: 扩展名返回&#xff1a; 文件路径列表"""newDir d…

侯捷 C++面向对象编程笔记——9 复合 委托

9 复合 委托 9.1 Composition 复合 类似于c中结构里有结构——class里有class deque 是一个已经存在的功能很多的类&#xff08;两头进出的队列&#xff09;&#xff1b;利用deque的功能来实现queue的多种操作 该例只是复合的一种情况——设计模式 Adapter 9.1.1 复合下的构造…

第一课-前提-Stable Diffusion 教程

学习 SD 的前提是电脑配置! SD 参考配置: 建议选择台式机 i5 CPU, 内存16GB,N卡 RTX3060, 8G显存以上的配置(最低配) 在此基础上的配置越高越好。 比如,cpu i7 更好,显卡能有 RTX4090 更好,32显存要能有最好,嘿嘿嘿。 如何查看自己的显卡配置? Win+R 输入 “dxdiag…

编译LightGBM错误处理记录

在LightGBM源码中新建文件夹build&#xff0c;然后在build目录下运行命令 cmake -A x64 -DUSE_GPU1 -DBOOST_ROOTC:\local\boost_1_82_0 -DBOOST_LIBRARYDIRC:\local\boost_1_82_0\lib64-msvc-14.3 .. 报错 错误原因&#xff1a; miniconda3\Library\lib\cmake\中boost版本是…

基于facenet+faiss开发构建人脸识别系统

facenet是一款非常经典的神经网络模型&#xff0c;它可以直接学习从人脸图像到欧几里德空间的映射(直接将人脸映射到欧几里得空间)。在欧几里德空间中&#xff0c;距离直接对应于人脸相似性的度量。一旦这个空间产生&#xff0c;使用标准技术&#xff0c;将FaceNet嵌入作为特征…

车载软件架构 —— 车载软件安全启动关键技术解读

车载软件架构 —— 车载软件安全启动关键技术解读 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 没有人关注你。也无需有人关注你。你必须承认自己的价值,你不能站在他人的角度来反对自己。人生…