当前位置: 首页 > news >正文

Linux进程10-有名管道概述、创建、读写操作、两个管道进程间通信、读写规律(只读、只写、读写区别)、设置阻塞/非阻塞

目录

1.有名管道

1.1概述

1.2与无名管道的差异

2.有名管道的创建 

2.1 直接用shell命令创建有名管道

2.2使用mkfifo函数创建有名管道

 3.有名管道读写操作

3.1单次读写

3.2多次读写

4.有名管道进程间通信

4.1回合制通信

4.2父子进程通信

5.有名管道读写规律(默认阻塞)

5.1读写端都存在,只读不写

5.2读写端都存在,只写不读

5.3 在一个进程中,只有读端,没有写端

5.4 在一个进程中,只有写端,没有读端

5.5 一个进程只读,一个进程只写

5.5.1两个进程,一个只读一个只写

5.5.2两个进程,一个只读一个只写,关闭写端

5.5.3两个进程,一个只读一个只写,关闭读端

5.6读写端都存在,默认阻塞

6.有名管道的读写规律(设置:非阻塞)

6.1只读方式打开(设置非阻塞)

6.2只写方式打开(设置非阻塞)

6.3读写方式打开(设置非阻塞)


1.有名管道

1.1概述

命名管道(FIFO)和管道(pipe)基本相同,但也有一些显著的不同,
其特点是:
1、半双工,数据在同一时刻只能在一个方向上流动。
2、写入FIFO中的数据遵循先入先出的规则。
3、FIFO所传送的数据是无格式的,这要求FIFO的读出方与写入方必须事先约定好数据的格
式,如多少字节算一个消息等。
4、FIFO在文件系统中作为一个特殊的文件而存在并且在文件系统中可见,所以有名管道可
以实现不相关进程间通信,但FIFO中的内容却存放在内存中。
5、管道在内存中对应一个缓冲区。不同的系统其大小不一定相同。
6、从FIFO读数据是一次性操作,数据一旦被读,它就从FIFO中被抛弃,释放空间以便写更
多的数据。
7、当使用FIFO的进程退出后,FIFO文件将继续保存在文件系统中以便以后使用。
8、FIFO有名字,不相关的进程可以通过打开命名管道进行通信。

1.2与无名管道的差异

特性有名管道无名管道
进程关系允许无亲缘关系的进程通信仅限有亲缘关系的进程
存在形式文件系统中的 FIFO 文件内存中的临时缓冲区
持久性文件删除前一直存在进程终止后自动销毁
创建方式mkfifo()/mkfifoat()pipe()

2.有名管道的创建 

2.1 直接用shell命令创建有名管道

在终端直接用shell命令mkfifo创建有名管道

使用ls -l命令查看 myfifo1文件的类型为p,表示该文件是一个管道文件。

2.2使用mkfifo函数创建有名管道

mkfifo函数原型:
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
功能:创建一个有名管道,产生一个本地文件系统可见的文件pathname参数:
pathname:有名管道创建后生成的文件,可以带路径
mode:管道文件的权限,一般通过八进制数设置即可,例如0664返回值:成功:0失败:‐1

(1)管道文件不存在

程序:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>int main(int argc, char const *argv[])
{//通过mkfifo函数创建有名管道if(mkfifo("fifo_file", 0664) == -1){perror("fail to mkfifo");exit(1);}return 0;
}

运行结果:管道文件不存在,创建了fifo_file管道文件

(2)管道文件存在

再次运行程序,报错:文件已存在

程序修改:如果错误码不是 EEXIST,继续运行

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>int main(int argc, char const *argv[])
{//通过mkfifo函数创建有名管道if(mkfifo("fifo_file", 0664) == -1){printf("errno = %d\n", errno);//如果管道文件已经存在,不需要报错退出,直接使用即可,//所以需要在错误输出之前把因为文件存在的错误排除if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}return 0;
}

运行结果:

终端输入: sudo find /usr/include -name "errno-base.h" ,查找错误码文件

 3.有名管道读写操作

由于有名管道在本地创建了一个管道文件,所以系统调用的IO函数基本都可以对有名管道

进行操作, 但是不能使用lseek修改管道文件的偏移量.

注意:有名管道创建的本地的文件只是起到标识作用,真正有名管道实现进程间通信还是在

内核空间开辟内存,所以本地产生的文件只是一个标识,没有其他作用,对本地管道文件的

操作实质就是对内核空间的操作。

3.1单次读写

程序:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>#define FIFONAME "fifo_file" //管道文件int main(int argc, char const *argv[])
{//通过mkfifo函数创建有名管道if(mkfifo(FIFONAME, 0664) == -1){if(errno != EEXIST)//如果不存在报错{perror("fail to mkfifo");exit(1);}}//对有名管道进行读写操作//通过open函数打开管道文件并得到文件描述符int fd;fd = open(FIFONAME, O_RDWR);//权限:可读可写if(fd == -1){perror("fail to open");exit(1);}//通过write函数向管道中写入数据if(write(fd, "hello world", strlen("hello world")) == -1){perror("fail to write");exit(1);}//通过read函数读取管道中的数据char buf[32] = "";if(read(fd, buf, sizeof(buf)) == -1){perror("fail to read");exit(1);}printf("buf = [%s]\n", buf);//使用close函数关闭文件描述符close(fd);return 0;
}

 运行结果:

3.2多次读写

程序:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>#define FIFONAME "fifo_file"int main(int argc, char const *argv[])
{//通过mkfifo函数创建有名管道if(mkfifo(FIFONAME, 0664) == -1){if(errno != EEXIST)//如果不存在报错{perror("fail to mkfifo");exit(1);}}//对有名管道进行操作//管道后写入的数据会保存在之前写入数据的后面,不会替换//如果管道中没有数据了,读操作会阻塞//通过open函数打开管道文件并得到文件描述符int fd;fd = open(FIFONAME, O_RDWR);if(fd == -1){perror("fail to open");exit(1);}//第一次 通过write函数向管道中写入数据if(write(fd, "hello world", strlen("hello world")) == -1){perror("fail to write");exit(1);}//第2次 通过write函数向管道中写入数据if(write(fd, "nihao", strlen("nihao")) == -1){perror("fail to write");exit(1);}//第1次 通过read函数读取管道中的数据,已将管道中的所有数据读取char buf[32] = "";if(read(fd, buf, sizeof(buf)) == -1){perror("fail to read");exit(1);}printf("第1次读取 buf = [%s]\n", buf);//第2次 通过read函数读取管道中的数据,管道中已无数据if(read(fd, buf, sizeof(buf)) == -1){perror("fail to read");exit(1);}printf("第2次读取 buf = [%s]\n", buf);//使用close函数关闭文件描述符close(fd);return 0;
}

运行结果:第1次 通过read函数读取管道中的数据,已将管道中的所有数据读取;第2次 通过read函数读取管道中的数据,管道中已无数据,read函数执行阻塞;

4.有名管道进程间通信

有名管道在本地创建了一个管道文件,所以不相关的进程间也可以实现通信。

4.1回合制通信

发送端程序:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main(int argc, char const *argv[])
{//如果没有创建有名管道,则创建有名管道//为了实现两个进程都可以收发数据,所以需要创建两个有名管道if(mkfifo("myfifo1", 0664) == -1){if(errno != EEXIST)//如果不存在报错{perror("fail to mkfifo");exit(1);//退出}}if(mkfifo("myfifo2", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//打开两个有名管道并得到文件描述符//fd_w:向管道myfifo1写入数据,fd_r:从管道myfifo2读取数据,//另一个接收方正好相反int fd_w, fd_r;if((fd_w = open("myfifo1", O_WRONLY)) == -1){perror("fail to open");exit(1);}if((fd_r = open("myfifo2", O_RDONLY)) == -1){perror("fail to open");exit(1);}char buf[128] = "";char buf1[128] = "";ssize_t bytes;while(1){printf("发送端运行中:请输入向接收端要发送的内容\n");fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = '\0';//将fgets最后输入的\n替换为\0,终端就没有空行//send进程负责将数据写入myfifo1,接着从myfifo2中读取数据//发送端将终端输入的数据写入myfifo1,接收端:myfifo2会读取写入的数据if((bytes = write(fd_w, buf, sizeof(buf))) == -1){perror("fail to write");exit(1);}//发送端从myfifo2读取数据if((bytes = read(fd_r, buf1, sizeof(buf1))) == -1){perror("fail to read");exit(1);}printf("发送端:读取到接收端发送的数据: %s\n", buf1);memset(buf, 0, sizeof(buf));//buf清0memset(buf1, 0, sizeof(buf1));}return 0;
}

接收端程序:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main(int argc, char const *argv[])
{if(mkfifo("myfifo1", 0664) == -1){if(errno != EEXIST)//如果不存在报错{perror("fail to mkfifo");exit(1);}}if(mkfifo("myfifo2", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//fd_w:向管道myfifo2写入数据,fd_r:从管道myfifo1读取数据,int fd_w, fd_r;if((fd_r = open("myfifo1", O_RDONLY)) == -1){perror("fail to open");exit(1);}if((fd_w = open("myfifo2", O_WRONLY)) == -1){perror("fail to open");exit(1);}char buf[128] = "";char buf1[128] = "";ssize_t bytes;while(1){//recv进程负责从myfifo1中读取数据,接着将终端输入数据写入myfifo2//接收端:读取myfifo1写入数据if((bytes = read(fd_r, buf, sizeof(buf))) == -1){perror("fail to read");exit(1);}printf("接收端:读取到发送端发送的数据: %s\n", buf);printf("接收端运行中,清输入要发送的内容: \n");fgets(buf1, sizeof(buf1), stdin);buf1[strlen(buf1) - 1] = '\0';//接收端:向myfifo2写入数据,发送端:myfifo1会读取写入的数据if((bytes = write(fd_w, buf1, sizeof(buf1))) == -1){perror("fail to write");exit(1);}memset(buf, 0, sizeof(buf));//buf清0memset(buf1, 0, sizeof(buf1));}return 0;
}

运行结果:打开两个终端,分别运行发送端和接收端程序。发送和接收端程序运行时,发送端:先给接收端发送数据,保存在管道1;接着等待从管道2读取接收端发送的数据。接收端:从管道1读取发送端发送的数据;接着向发送端发送数据,保存在管道2。

程序缺点:只能一端输出后,等待另一端回复;回合制发送和接收

优化:选择父子进程。一个用于发送,一个用于接收。

(1)发送端

(2)接收端

4.2父子进程通信

(1)发送端程序:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main(int argc, char const *argv[])
{//如果没有创建有名管道,则创建有名管道//为了实现两个进程都可以收发数据,所以需要创建两个有名管道if(mkfifo("myfifo1", 0664) == -1){if(errno != EEXIST)//如果不存在报错{perror("fail to mkfifo");exit(1);//退出}}if(mkfifo("myfifo2", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//打开两个有名管道并得到文件描述符//fd_w:向管道myfifo1写入数据,fd_r:从管道myfifo2读取数据,//另一个接收方正好相反int fd_w, fd_r;if((fd_w = open("myfifo1", O_WRONLY)) == -1){perror("fail to open");exit(1);}if((fd_r = open("myfifo2", O_RDONLY)) == -1){perror("fail to open");exit(1);}char buf[128] = "";char buf1[128] = "";ssize_t bytes;//使用fork函数创建子进程pid_t pid;if((pid = fork()) < 0){perror("fail to fork");exit(1);}else if(pid > 0) // 父进程{while(1){printf("发送端运行中:请输入向接收端要发送的内容\n");fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = '\0';//将fgets最后输入的\n替换为\0,终端就没有空行//send进程负责将数据写入myfifo1,接着从myfifo2中读取数据//发送端将终端输入的数据写入myfifo1,接收端:myfifo2会读取写入的数据if((bytes = write(fd_w, buf, sizeof(buf))) == -1){perror("fail to write");exit(1);}memset(buf, 0, sizeof(buf));//buf清0sleep(1);}}else // 子进程{while(1){//发送端从myfifo2读取数据if((bytes = read(fd_r, buf1, sizeof(buf1))) == -1){perror("fail to read");exit(1);}printf("发送端:读取到接收端发送的数据: %s\n", buf1);	if(strcmp("end_end",buf1) == 0){printf("发送端:读取到接收端发送的: 终止信号,退出\n");exit(1);}memset(buf1, 0, sizeof(buf1));sleep(1);}}return 0;
}

(2)接收端程序

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>int main(int argc, char const *argv[])
{//如果没有创建有名管道,则创建有名管道//为了实现两个进程都可以收发数据,所以需要创建两个有名管道if(mkfifo("myfifo1", 0664) == -1){if(errno != EEXIST)//如果不存在报错{perror("fail to mkfifo");exit(1);//退出}}if(mkfifo("myfifo2", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//打开两个有名管道并得到文件描述符//fd_w:向管道myfifo1写入数据,fd_r:从管道myfifo2读取数据,//另一个接收方正好相反int fd_w, fd_r;if((fd_w = open("myfifo1", O_WRONLY)) == -1){perror("fail to open");exit(1);}if((fd_r = open("myfifo2", O_RDONLY)) == -1){perror("fail to open");exit(1);}char buf[128] = "";char buf1[128] = "";ssize_t bytes;//使用fork函数创建子进程pid_t pid;if((pid = fork()) < 0){perror("fail to fork");exit(1);}else if(pid > 0) // 父进程{while(1){printf("发送端运行中:请输入向接收端要发送的内容\n");fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = '\0';//将fgets最后输入的\n替换为\0,终端就没有空行//send进程负责将数据写入myfifo1,接着从myfifo2中读取数据//发送端将终端输入的数据写入myfifo1,接收端:myfifo2会读取写入的数据if((bytes = write(fd_w, buf, sizeof(buf))) == -1){perror("fail to write");exit(1);}memset(buf, 0, sizeof(buf));//buf清0sleep(1);}}else // 子进程{while(1){//发送端从myfifo2读取数据if((bytes = read(fd_r, buf1, sizeof(buf1))) == -1){perror("fail to read");exit(1);}printf("发送端:读取到接收端发送的数据: %s\n", buf1);	if(strcmp("end_end",buf1) == 0){printf("发送端:读取到接收端发送的: 终止信号,退出\n");exit(1);}memset(buf1, 0, sizeof(buf1));sleep(1);}}return 0;
}

运行结果:打开两个终端,分别运行发送端和接收端程序。发送和接收端程序运行时,发送端既可以接收多次数据,也可以发送多次数据;接收端也支持同时发送和接收多次数据。发送特殊字符end_end退出运行。

(1)发送端

(2)接收端

5.有名管道读写规律(默认阻塞)

5.1读写端都存在,只读不写

程序:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{if(mkfifo("myfifo", 0664) == -1){//如果管道文件已经存在,不需要报错退出,直接使用即可,//所以需要在错误输出之前把因为文件存在的错误排除if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//读写端都存在,只读不写//如果原本管道中有数据,则正常读取//如果管道中没有数据,则read函数会阻塞等待int fd;if((fd = open("myfifo", O_RDWR)) == -1){perror("fail to open");exit(1);}//先写入数据验证,管道中有数据,则正常读取write(fd, "hello world", 11);char buf[128] = "";read(fd, buf, sizeof(buf));printf("buf = %s\n", buf);//管道中已无数据,读取会阻塞。read(fd, buf, sizeof(buf));printf("buf = %s\n", buf);return 0;
}

运行结果:读写端都存在,只读不写。

第一次读取,管道中有数据,正常读取;第二次读取,管道中已经无数据,在read处阻塞。

5.2读写端都存在,只写不读

程序:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{//如果管道文件已经存在,不需要报错退出,直接使用即可,//所以需要在错误输出之前把因为文件存在的错误排除if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//读写端都存在,只写不读//当有名管道的缓冲区写满后,write函数会发生阻塞//默认有名管道的缓冲区为64K字节int fd;if((fd = open("myfifo", O_RDWR)) == -1){perror("fail to open");exit(1);}int num = 0;while(1){write(fd, "", 1024);num++;printf("num = %d\n", num);}return 0;
}

运行结果:读写端都存在,只写不读 ;当有名管道的缓冲区写满后,write函数会发生阻塞;默认有名管道的缓冲区为64K字节。

5.3 在一个进程中,只有读端,没有写端

程序:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//在一个进程中,只有读端,没有写端//会在open函数的位置阻塞printf("***********************\n");int fd;if((fd = open("myfifo", O_RDONLY)) == -1){perror("fail to open");exit(1);}printf("------------------------\n");char buf[128] = "";ssize_t bytes;if((bytes = read(fd, buf, sizeof(buf))) == -1){perror("fail to read");exit(1);}printf("bytes = %ld\n", bytes);printf("buf = %s\n", buf);return 0;
}

运行结果:在一个进程中,只有读端,没有写端;会在open函数的位置阻塞(printf("------------------------\n"); 未执行)。

5.4 在一个进程中,只有写端,没有读端

程序:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{//如果管道文件已经存在,不需要报错退出,直接使用即可,//所以需要在错误输出之前把因为文件存在的错误排除if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//在一个进程中,只有写端,没有读端//会在open函数的位置阻塞printf("*****************************\n");int fd;if((fd = open("myfifo", O_WRONLY)) == -1){perror("fail to open");exit(1);}printf("-----------------------------\n");write(fd, "hello world", 11);printf("666\n");sleep(1);return 0;
}

运行结果:在一个进程中,只有写端,没有读端;会在open函数的位置阻塞

5.5 一个进程只读,一个进程只写

5.5.1两个进程,一个只读一个只写

只要保证有名管道的 读写端都存在 ,不管是几个进程,都 不会再open这阻塞 了。
(1)只读程序
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//在一个进程中,只有读端,没有写端//会在open函数的位置阻塞printf("***********************\n");int fd;if((fd = open("myfifo", O_RDONLY)) == -1){perror("fail to open");exit(1);}printf("------------------------\n");char buf[128] = "";ssize_t bytes;if((bytes = read(fd, buf, sizeof(buf))) == -1){perror("fail to read");exit(1);}printf("bytes = %ld\n", bytes);printf("buf = %s\n", buf);return 0;
}

(2)只写程序

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{//如果管道文件已经存在,不需要报错退出,直接使用即可,//所以需要在错误输出之前把因为文件存在的错误排除if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//在一个进程中,只有写端,没有读端//会在open函数的位置阻塞printf("*****************************\n");int fd;if((fd = open("myfifo", O_WRONLY)) == -1){perror("fail to open");exit(1);}printf("-----------------------------\n");write(fd, "hello world", 11);printf("666\n");sleep(1);return 0;
}

运行结果:打开2个终端,对同一个管道进行读写操作,读写端同时存在,程序没有阻塞在open。

(1)只写端,程序没有阻塞在open,(printf("------------------------\n"); 已执行)

(2)只读端,程序没有阻塞在open,(printf("------------------------\n"); 已执行)

5.5.2两个进程,一个只读一个只写,关闭写端

如果一个进程只读,一个进程只写,都运行后,如果关闭写端,读端read会返回0。
(1)只写端程序
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//在一个进程中,只有写端,没有读端//会在open函数的位置阻塞printf("*****************************\n");int fd;if((fd = open("myfifo", O_WRONLY)) == -1){perror("fail to open");exit(1);}printf("-----------------------------\n");while(1){write(fd, "hello world", 11);printf("666\n");sleep(1);}return 0;
}
(2)只读端程序
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>int main(int argc, char const *argv[])
{if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//在一个进程中,只有读端,没有写端//会在open函数的位置阻塞printf("***********************\n");int fd;if((fd = open("myfifo", O_RDONLY)) == -1){perror("fail to open");exit(1);}printf("------------------------\n");char buf[128] = "";ssize_t bytes;while(1){if((bytes = read(fd, buf, sizeof(buf))) == -1){perror("fail to read");exit(1);}printf("bytes = %ld\n", bytes);printf("buf = %s\n", buf);sleep(1);}return 0;
}

运行结果:打开两个终端运行。一个进程只读,一个进程只写,都运行后,如果关闭写端,读端read会返回0。

(1)写端,运行几次后,关闭写端,终止运行。

(2)读端,关闭写端,读端read会返回0。

5.5.3两个进程,一个只读一个只写,关闭读端

如果一个进程只读,一个进程只写,都运行后, 如果关闭读端,写端会立即产生 SIGPIPE信号(管道破裂),默认的处理方式是退出进程
(1)只写端程序
与5.5.2两个进程,一个只读一个只写,关闭写端;程序相同。
(2)只读端程序
与5.5.2两个进程,一个只读一个只写,关闭写端;程序相同。
运行结果:打开两个终端运行
(1)读端,关闭后,写端产 生SIGPIPE信号(管道破裂),默认的处理方式是退出进程。
(2)写端

5.6读写端都存在,默认阻塞

有名管道默认读写状态为阻塞,读写端同时存在,不会再open函数处阻塞

程序:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>int main(int argc, char *argv[])
{int fd;if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//如果open设置为可读可写,默认:阻塞效果char send[100] = "nihao world";fd = open("myfifo", O_RDWR);//读写打开if(fd < 0){perror("fail open fifo");exit(1);}write(fd, send, strlen(send));char recv[100] = "";read(fd, recv, sizeof(recv));printf("read from my_fifo buf=[%s]\n",recv);return 0;
}
运行结果:有名管道默认读写状态为阻塞,读写端同时存在,不会再open函数处阻塞。

6.有名管道的读写规律(设置:非阻塞)

指定 O_NONBLOCK( open 位或 O_NONBLOCK)
1 、先以只读方式打开:如果没有进程已经为写而打开一个 FIFO, 只读 open 成功,并且 open 不阻塞。
2 、先以只写方式打开:如果没有进程已经为读而打开一个 FIFO ,只写 open 将出错返回 -1
3 read write 读写命名管道中读数据时不阻塞。
4 、通信过程中,读进程退出后,写进程向命名管道内写数据时,写进程也会(收到 SIGPIPE 信号)退出。

6.1只读方式打开(设置非阻塞)

程序:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>int main(int argc, char *argv[])
{int fd;if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//如果open标志位设置为非阻塞,并且以只读的方式打开管道文件//open函数和read函数都不会阻塞fd = open("myfifo", O_RDONLY | O_NONBLOCK);if(fd < 0){perror("fail open fifo");exit(1);}while(1){char recv[100] = "";bzero(recv, sizeof(recv));read(fd, recv, sizeof(recv));printf("read from my_fifo buf=[%s]\n",recv);sleep(1);}return 0;
}

运行结果:管道只读 非阻塞打开,在 open函数 不阻塞,程序继续运行。

6.2只写方式打开(设置非阻塞)

程序:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>int main(int argc, char *argv[])
{int fd;if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//如果open标志位设置为非阻塞,并且以只写的方式打开管道文件//open函数会直接报错//如果open设置为可读可写,那么跟阻塞是一样的效果char send[100] = "Hello world";fd = open("myfifo", O_WRONLY | O_NONBLOCK);//fd = open("myfifo", O_RDWR | O_NONBLOCK);if(fd < 0){perror("fail open fifo");exit(1);}write(fd, send, strlen(send));char recv[100] = "";read(fd, recv, sizeof(recv));printf("read from my_fifo buf=[%s]\n",recv);return 0;
}

运行结果:管道只写 非阻塞打开管道文件,open函数会直接报错。(不加非阻塞设置,在open函数处,阻塞。见5.4章节)

6.3读写方式打开(设置非阻塞)

程序:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>int main(int argc, char *argv[])
{int fd;if(mkfifo("myfifo", 0664) == -1){if(errno != EEXIST){perror("fail to mkfifo");exit(1);}}//如果open设置为可读可写,那么跟阻塞是一样的效果char send[100] = "Hello world";//fd = open("myfifo", O_WRONLY | O_NONBLOCK);fd = open("myfifo", O_RDWR | O_NONBLOCK);//读写打开if(fd < 0){perror("fail open fifo");exit(1);}write(fd, send, strlen(send));char recv[100] = "";read(fd, recv, sizeof(recv));printf("read from my_fifo buf=[%s]\n",recv);return 0;
}

运行结果:读写端同时存在,设置为非阻塞,不会再open函数处阻塞。效果与读写端同时存在,设置为阻塞,效果相同。

相关文章:

Linux进程10-有名管道概述、创建、读写操作、两个管道进程间通信、读写规律(只读、只写、读写区别)、设置阻塞/非阻塞

目录 1.有名管道 1.1概述 1.2与无名管道的差异 2.有名管道的创建 2.1 直接用shell命令创建有名管道 2.2使用mkfifo函数创建有名管道 3.有名管道读写操作 3.1单次读写 3.2多次读写 4.有名管道进程间通信 4.1回合制通信 4.2父子进程通信 5.有名管道读写规律&#xff…...

高吞吐与低延迟的博弈:Kafka与RabbitMQ数据管道实战指南

摘要 本文全面对比Apache Kafka与RabbitMQ在数据管道中的设计哲学、核心差异及协同方案。结合性能指标、应用场景和企业级实战案例&#xff0c;揭示Kafka在高吞吐流式处理中的优势与RabbitMQ在复杂路由和低延迟传输方面的独特特点&#xff1b;介绍了使用Java生态成熟第三方库&…...

C++23 views::slide (P2442R1) 深入解析

文章目录 引言C20 Ranges库回顾什么是Rangesstd::views的作用 views::slide 概述基本概念原型定义辅助概念工作原理代码示例输出结果 views::slide 的应用场景计算移动平均值查找连续的子序列 总结 引言 在C的发展历程中&#xff0c;每一个新版本都会带来一系列令人期待的新特…...

SpringDataRedis的入门案例,以及RedisTemplate序列化实现

目录 SpringDataRedis 简单介绍 入门案例 RedisTemplate序列化方案 方案一: 方案二: SpringDataRedis 简单介绍 提供了对不同Redis客户端的整合(Lettuce和Jedis) 提供了RedisTemplate统一API来操作Redis 支持Redis的发布订阅模型 支持Redis哨兵和Redis集群 支持基于…...

鸿蒙HarmonyOS list优化一: list 结合 lazyforeach用法

list列表是开发中不可获取的&#xff0c;非常常用的组件&#xff0c;使用过程中会需要不断的优化&#xff0c;接下来我会用几篇文章进行list在纯原生的纯血鸿蒙的不断优化。我想进大厂&#xff0c;希望某位大厂的看到后能给次机会。 首先了解一下lazyforeach&#xff1a; Laz…...

【Jenkins简单自动化部署案例:基于Docker和Harbor的自动化部署流程记录】

摘要 本文记录了作者使用Jenkins时搭建的一个简单自动化部署案例&#xff0c;涵盖Jenkins的Docker化安装、Harbor私有仓库配置、Ansible远程部署等核心步骤。通过一个SpringBoot项目 (RuoYi) 的完整流程演示&#xff0c;从代码提交到镜像构建、推送、滚动更新&#xff0c;逐步实…...

【愚公系列】《Manus极简入门》034-跨文化交流顾问:“文化桥梁使者”

&#x1f31f;【技术大咖愚公搬代码&#xff1a;全栈专家的成长之路&#xff0c;你关注的宝藏博主在这里&#xff01;】&#x1f31f; &#x1f4e3;开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主&#xff01; &#x1f…...

数字滤波器应用介绍

此示例说明如何设计、分析数字过滤器并将其应用于数据。它将帮助您回答以下问题: 如何补偿滤波器引入的延迟?如何避免使信号失真?如何从信号中删除不需要的内容?如何微分信号?以及积分信号文章目录 补偿筛选引入的延迟补偿恒定滤波器延迟 如FIR引起的消除方法,末尾添零补…...

木马查杀篇—Opcode提取

【前言】 介绍Opcode的提取方法&#xff0c;并探讨多种机器学习算法在Webshell检测中的应用&#xff0c;理解如何在实际项目中应用Opcode进行高效的Webshell检测。 Ⅰ 基本概念 Opcode&#xff1a;计算机指令的一部分&#xff0c;也叫字节码&#xff0c;一个php文件可以抽取出…...

栈和队列复习(C语言版)

目录 一.栈的概念 二.栈的实现 三.队列的概念 四.队列的实现 五.循环队列的实现 一.栈的概念 可以将栈抽象地理解成羽毛球桶&#xff0c;或者理解成坐直升电梯&#xff1b;最后一个进去的&#xff0c;出来时第一个出来&#xff0c;并且只有一个出入口。这边需要注意的是&am…...

SDK does not contain ‘libarclite‘ at the path

Xcode16以上版本更新SDK之后就报错了。是因为缺少libarclite_iphoneos.a文件。所以需要在网上找一下该文件根据路径添加进去&#xff0c;arc文件可能需要新建一下。 clang: error: SDK does not contain ‘libarclite’ at the path ‘/Applications/Xcode.app/Contents/Develo…...

Kotlin跨平台Compose Multiplatform实战指南

Kotlin Multiplatform&#xff08;KMP&#xff09;结合 Compose Multiplatform 正在成为跨平台开发的热门选择&#xff0c;它允许开发者用一套代码构建 Android、iOS、桌面&#xff08;Windows/macOS/Linux&#xff09;和 Web 应用。以下是一个实战指南&#xff0c;涵盖核心概念…...

Oracle数据库全局性HANG的处理过程

如果Oracle数据库全局性HANG&#xff0c;首先要做的就是收集数据库HANG时的状态&#xff0c;只有收集到了相应状态&#xff0c;抓住故障现场&#xff0c;才可以进一步分析故障产生的可能原因。 出现此故障&#xff0c;一般情况下可以如此处理&#xff1a; 如果数据库是单节点&a…...

MySQL 8.0 OCP(1Z0-908)英文题库(21-30)

目录 第21题题目分析正确答案 第22题题目分析正确答案 第23题题目分析正确答案 第24题题目分析正确答案 第25题题目分析正确答案 第26题题目分析正确答案 第27题题目分析正确答案 第28题题目分析正确答案 第29题题目分析正确答案 第30题题目解析正确答案 第21题 Choose three.…...

beyond compare 免密钥进入使用(删除注册表)

beyond compare 免密钥进入&#xff0c;免费使用&#xff08;删除注册表&#xff09; 温馨提醒&#xff1a;建议仅个人使用&#xff0c;公司使用小心律师函警告&#xff01; 1.winr 输入regedit 打开注册表 2.删除计算机 \HKEY_CURRENT_USER\Software\Scooter Software\Beyo…...

前端项目2-01:个人简介页面

目录 一.代码显示 二.效果图 三.代码分析 1. 文档声明和 HTML 基本结构 2. CSS 样式部分 全局样式 body 样式 页面主要容器 box 样式 左侧区域 l 样式 右侧区域 r 样式 左侧区域中头像容器 to 样式 头像图片样式及悬停效果 左侧区域中个人信息容器 tit 样式 个人…...

.NET 8 API 实现websocket,并在前端angular实现调用

.NET 8 API 实现websocket&#xff0c;并在前端angular实现调用。 后端&#xff1a;.NET 8 WebSocket API 实现 在 .NET 8 中&#xff0c;可以通过 Microsoft.AspNetCore.WebSockets 提供的支持来实现 WebSocket 功能。以下是创建一个简单的 WebSocket 控制器的步骤。 安装必…...

P2P架构

P2P 是 Peer-to-Peer&#xff08;点对点&#xff09; 的缩写&#xff0c;是一种 去中心化 的网络架构&#xff0c;其中每个节点&#xff08;称为 “对等节点”&#xff0c;Peer&#xff09;既是 “客户端”&#xff0c;也是 “服务器”&#xff0c;可以直接与其他节点通信、共享…...

菊厂0510面试手撕题目解答

题目 输入一个整数数组&#xff0c;返回该数组中最小差出现的次数。 示例1&#xff1a;输入&#xff1a;[1,3,7,5,9,12]&#xff0c;输出&#xff1a;4&#xff0c;最小差为2&#xff0c;共出现4次&#xff1b; 示例2&#xff1a;输入&#xff1a;[90,98,90,90,1,1]&#xf…...

【25软考网工】第六章(4)VPN虚拟专用网 L2TP、PPTP、PPP认证方式;IPSec、GRE

博客主页&#xff1a;christine-rr-CSDN博客 ​专栏主页&#xff1a;软考中级网络工程师笔记 ​​ 大家好&#xff0c;我是christine-rr !目前《软考中级网络工程师》专栏已经更新二十多篇文章了&#xff0c;每篇笔记都包含详细的知识点&#xff0c;希望能帮助到你&#xff01…...

C语言:深入理解指针(3)

目录 一、数组名的理解 二、用指针访问数组 三、一维数组传参的本质 四、冒泡排序 五、二级指针 六、指针数组 七、指针数组模拟二维数组 八、结语 一、数组名的理解 数组名其实就是首元素的地址 int arr[3] {1,2,3}; printf("arr :%p\n" ,arr); printf(…...

R语言实战第5章(1)

第一部分&#xff1a;数学、统计和字符处理函数 数学和统计函数&#xff1a;R提供了丰富的数学和统计函数&#xff0c;用于执行各种计算和分析。这些函数可以帮助用户快速完成复杂的数学运算、统计分析等任务&#xff0c;例如计算均值、方差、相关系数、进行假设检验等。字符处…...

Lodash isEqual 方法源码实现分析

Lodash isEqual 方法源码实现分析 Lodash 的 isEqual 方法用于执行两个值的深度比较&#xff0c;以确定它们是否相等。这个方法能够处理各种 JavaScript 数据类型&#xff0c;包括基本类型、对象、数组、正则表达式、日期对象等&#xff0c;并且能够正确处理循环引用。 1. is…...

探索边缘计算:赋能物联网的未来

摘要 随着物联网&#xff08;IoT&#xff09;技术的飞速发展&#xff0c;越来越多的设备接入网络&#xff0c;产生了海量的数据。传统的云计算模式在处理这些数据时面临着延迟高、带宽不足等问题&#xff0c;而边缘计算的出现为解决这些问题提供了新的思路。本文将深入探讨边缘…...

Ubuntu中配置【Rust 镜像源】

本篇主要记录Ubuntu中配置Rust编程环境时&#xff0c;所需要做的镜像源相关的配置 无法下载 Rust 工具链 通过环境变量指定 Rust 的国内镜像源&#xff08;如中科大或清华源&#xff09;。 方法一&#xff1a;临时设置镜像 export RUSTUP_DIST_SERVERhttps://mirrors.ustc.e…...

netty 客户端发送消息服务端收到消息无法打印,springBoot配合 lombok使用@Slf4j

netty 客户端发送消息服务端收到消息无法打印&#xff0c;springBoot配合 lombok使用Slf4j 服务端代码 Slf4j public class EventLoopServer {public static void main(String[] args) throws InterruptedException {new ServerBootstrap().group(new NioEventLoopGroup()).c…...

学习笔记:黑马程序员JavaWeb开发教程(2025.4.3)

12.1 基础登录功能 EmpService中的login方法&#xff0c;是根据接收到的用户名和密码&#xff0c;查询时emp数据库中的员工信息&#xff0c;会返回一个员工对象。使用了三元运算符来写返回 Login是登录&#xff0c;是一个业务方法&#xff0c;mapper接口是持久层&#xff0c;是…...

Spark SQL 运行架构详解(专业解释+番茄炒蛋例子解读)

1. 整体架构概览 Spark SQL的运行过程可以想象成一个"SQL查询的加工流水线"&#xff0c;从原始SQL语句开始&#xff0c;经过多个阶段的处理和优化&#xff0c;最终变成分布式计算任务执行。主要流程如下&#xff1a; SQL Query → 解析 → 逻辑计划 → 优化 → 物理…...

【时时三省】(C语言基础)字符数组的输入输出

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 字符数组的输入输出可以有两种方法。 ( 1 )逐个字符输入输出。用格式符“% c”输入或输出一个字符. ( 2 )将整个字符串一次输入或输出。用“% s”格式符&#xff0c;意思是对字符串( strin…...

Hive HA配置高可用

Hive的高可用性(HA)通过消除关键组件的单点故障来实现,确保系统在部分故障时仍能正常运行。其基本原理涉及以下核心组件和策略: ‌1. Hive Metastore 的高可用‌ ‌ 多实例部署‌:部署多个Metastore服务实例,每个实例连接到共享的后端数据库(如MySQL、PostgreSQ…...

Python爬虫第20节-使用 Selenium 爬取小米商城空调商品

目录 前言 一、 本文目标 二、环境准备 2.1 安装依赖 2.2 配置 ChromeDriver 三、小米商城页面结构分析 3.1 商品列表结构 3.2 分页结构 四、Selenium 自动化爬虫实现 4.1 脚本整体结构 4.2 代码实现 五、关键技术详解 5.1 Selenium 启动与配置 5.2 页面等待与异…...

重构金融数智化产业版图:中电金信“链主”之道

近日&#xff0c;《商学院》杂志独家专访了中电金信常务副总经理&#xff08;主持经营工作&#xff09;冯明刚&#xff0c;围绕“金融科技”“数字底座”“架构转型”“AI驱动”等议题&#xff0c;展开了一场关于未来架构、技术变革与系统创新的深入对话。 当下&#xff0c;数字…...

笔记本电脑升级实战手册【扩展篇1】:flash id查询硬盘颗粒

文章目录 前言&#xff1a;一、硬盘颗粒介绍1、MLC&#xff08;Multi-Level Cell&#xff09;2、TLC&#xff08;Triple-Level Cell&#xff09;3、QLC&#xff08;Quad-Level Cell&#xff09; 二、硬盘与主控1、主控介绍2、主流主控厂家 三 、硬盘颗粒查询使用flash id工具查…...

文档外发安全:企业数据防护的最后一道防线

在当今数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。随着网络安全威胁日益增多&#xff0c;企业安装专业加密软件已从"可选"变为"必选"。本文将全面分析企业部署华途加密解决方案后获得的各项战略优势。 一、数据安全防护升级 核心数据全面保护…...

springboot集成langchain4j实现票务助手实战

前言 看此篇的前置知识为langchain4j整合springboot&#xff0c;以及springboot集成langchain4j记忆对话。 Function-Calls介绍 langchain4j 中的 Function Calls&#xff08;函数调用&#xff09;是一种让大语言模型&#xff08;LLM&#xff09;与外部工具&#xff08;如 A…...

ZYNQ笔记(二十一): VDMA HDMI 彩条显示

版本&#xff1a;Vivado2020.2&#xff08;Vitis&#xff09; 任务&#xff1a;实现驱动 HDMI 显示彩条图像&#xff0c;同时支持输出给 HDMI 的图像分辨率可调。 目录 一、介绍 二、硬件设计 &#xff08;1&#xff09;DVI_Transmitter &#xff08;2&#xff09;Clockin…...

常用的maven插件及其使用指南

目录 1.maven官方插件列表2.两种方式调用maven插件3.常用的maven插件总结参考文献 1.maven官方插件列表 groupId为org.apache.maven.pluginshttp://maven.apache.org/plugins/index.html 2.两种方式调用maven插件 将插件目标与生命周期阶段绑定&#xff0c;例如maven默认将m…...

Meilisearch 安装

1.环境 rockey linux 9.2 meilisearch-linux-amd64 2.下载 访问&#xff1a;https://github.com/meilisearch/meilisearch/releases 下载适合自己系统版本的。 注意&#xff1a;我下载的不是最新版本的&#xff0c;因为最新版本的需要GLIBC2.35&#xff0c;我本地系统的是…...

用postman的时候如何区分服务器还是自己的问题?

作为测试人员,在使用Postman进行接口测试时,准确判断问题是出在服务器端还是本地环境非常重要。以下是一些实用的区分方法: 1. 基础检查方法 本地问题排查清单: ✅ 检查网络连接是否正常 ✅ 确认Postman版本是否为最新 ✅ 验证请求URL是否正确(特别是环境变量是否被正确…...

【Python算法】最长递增子序列

题目链接 方法1&#xff1a; 记忆化搜索 class Solution:def lengthOfLIS(self, nums: List[int]) -> int:cachedef dfs(i):res0 for j in range(i):if nums[j]<nums[i]:res max(res,dfs(j))return res1 # 返回res表示以nums[i]结尾的LIS长度return max(dfs(i) for i…...

springboot-web基础

21.web spring MVC 基于浏览器的 B/S 结构应用十分流行。Spring Boot 非常适合 Web 应用开发。可以使用嵌入式 Tomcat、Jetty、 Undertow 或 Netty 创建一个自包含的 HTTP 服务器。一个 Spring Boot 的 Web 应用能够自己独立运行&#xff0c;不依赖需 要安装的 Tomcat&#x…...

解构赋值

【系统学习ES6】 本专题旨在对ES6的常用技术点进行系统性梳理&#xff0c;帮助大家对其有更好的掌握&#xff0c;希望大家有所收获。 ES6允许按照一定模式&#xff0c;从数组和对象中提取值&#xff0c;对变量进行赋值&#xff0c;这被称为解构。解构是一种打破数据结构&#x…...

Leetcode-BFS问题

LeetCode-BFS问题 1.Floodfill问题 1.图像渲染问题 [https://leetcode.cn/problems/flood-fill/description/](https://leetcode.cn/problems/flood-fill/description/) class Solution {public int[][] floodFill(int[][] image, int sr, int sc, int color) {//可以借助另一…...

AI 时代 UI 设计的未来范式

在人工智能技术持续突破的浪潮下&#xff0c;UI 设计领域正经历着前所未有的变革。AI 的深度介入不仅重塑了设计流程&#xff0c;更催生了全新的设计范式&#xff0c;为用户带来颠覆式的交互体验。探索 AI 时代 UI 设计的未来范式&#xff0c;是把握行业发展趋势的关键所在。​…...

键盘输出希腊字符方法

在不同操作系统中&#xff0c;输出希腊字母的方法有所不同。以下是针对 Windows 和 macOS 系统的详细方法&#xff0c;以及一些通用技巧&#xff1a; 1.Windows 系统 1.1 使用字符映射表 字符映射表是一个内置工具&#xff0c;可以方便地找到并插入希腊字母。 • 步骤&#xf…...

[数据结构高阶]并查集初识、手撕、可以解决哪类问题?

标题&#xff1a;[数据结构高阶]并查集初识、手撕、可以解决哪类问题&#xff1f; 水墨不写bug 文章目录 一、认识并查集二、模拟实现并查集三、用并查集解决问题1、[省份的数量](https://leetcode.cn/problems/number-of-provinces/)2、[等式方程的可满足性](https://leetcode…...

BUUCTF——PYWebsite

BUUCTF——PYWebsite 进入靶场 看看基本信息 没有什么信息 扫个目录看看 http://node5.buuoj.cn:28115/.DS_Store http://node5.buuoj.cn:28115/flag.php http://node5.buuoj.cn:28115/index.html访问flag.php 提示保存购买者的IP 抓包看看 直接XFF伪造一下 X-Forwarded-F…...

【学习笔记】机器学习(Machine Learning) | 第六章(2)| 过拟合问题

机器学习&#xff08;Machine Learning&#xff09; 简要声明 基于吴恩达教授(Andrew Ng)课程视频 BiliBili课程资源 文章目录 机器学习&#xff08;Machine Learning&#xff09;简要声明 解决过拟合问题一、收集更多训练数据二、选择特征三、正则化四、过拟合解决方法总结 过…...

单片机-STM32部分:13-1、编码器

飞书文档https://x509p6c8to.feishu.cn/wiki/BpEywhaX9iqbiLkdqdAcmDnwnab EC旋转编码器 在产品开发过程中&#xff0c;需要位置闭环的的产品&#xff0c;类似电机类产品来说&#xff0c;编码器至关重要&#xff0c;它不仅可以使我们对带年纪进行精确的速度闭环&#xff0c;位…...

浅谈大语言模型原理

1.反向传播算法 背景 反向传播算法是当前深度学习的核心技术。 神经网络 x是输入&#xff0c;o是输出&#xff0c;w是需要训练的参数&#xff08;w有初始值&#xff09;三层全连接的神经网络&#xff1a;输入层、隐藏层、输出层 激活函数 f ( x ) 1 1 x − 1 f(x)\frac…...