匿名管道

我们先来看,我们常用的匿名管道(Anonymous Pipes),也即将多个命令串起来的竖线,背后的原理到底是什么。

上次我们说,它是基于管道的,那管道如何创建呢?管道的创建,需要通过下面这个系统调用。

int pipe(int fd[2])

在这里,我们创建了一个管道 pipe,返回了两个文件描述符,这表示管道的两端,一个是管道的读取端描述符 fd[0],另一个是管道的写入端描述符 fd[1]。

我们来看在内核里面是如何实现的。

 

SYSCALL_DEFINE1(pipe, int __user *, fildes)
{return sys_pipe2(fildes, 0);
}SYSCALL_DEFINE2(pipe2, int __user *, fildes, int, flags)
{struct file *files[2];int fd[2];int error;error = __do_pipe_flags(fd, files, flags);if (!error) {if (unlikely(copy_to_user(fildes, fd, sizeof(fd)))) {
......error = -EFAULT;} else {fd_install(fd[0], files[0]);fd_install(fd[1], files[1]);}}return error;
}

在内核中,主要的逻辑在 pipe2 系统调用中。这里面要创建一个数组 files,用来存放管道的两端的打开文件,另一个数组 fd 存放管道的两端的文件描述符。如果调用 __do_pipe_flags 没有错误,那就调用 fd_install,将两个 fd 和两个 struct file 关联起来。这一点和打开一个文件的过程很像了。

我们来看 __do_pipe_flags。这里面调用了 create_pipe_files,然后生成了两个 fd。从这里可以看出,fd[0] 是用于读的,fd[1] 是用于写的。

static int __do_pipe_flags(int *fd, struct file **files, int flags)
{int error;int fdw, fdr;
......error = create_pipe_files(files, flags);
......error = get_unused_fd_flags(flags);
......fdr = error;error = get_unused_fd_flags(flags);
......fdw = error;fd[0] = fdr;fd[1] = fdw;return 0;
......
}

创建一个管道,大部分的逻辑其实都是在 create_pipe_files 函数里面实现的。这一章第一节的时候,我们说过,命名管道是创建在文件系统上的。从这里我们可以看出,匿名管道,也是创建在文件系统上的,只不过是一种特殊的文件系统,创建一个特殊的文件,对应一个特殊的 inode,就是这里面的 get_pipe_inode。

int create_pipe_files(struct file **res, int flags)
{int err;struct inode *inode = get_pipe_inode();struct file *f;struct path path;
......path.dentry = d_alloc_pseudo(pipe_mnt->mnt_sb, &empty_name);
......path.mnt = mntget(pipe_mnt);d_instantiate(path.dentry, inode);f = alloc_file(&path, FMODE_WRITE, &pipefifo_fops);
......f->f_flags = O_WRONLY | (flags & (O_NONBLOCK | O_DIRECT));f->private_data = inode->i_pipe;res[0] = alloc_file(&path, FMODE_READ, &pipefifo_fops);
......path_get(&path);res[0]->private_data = inode->i_pipe;res[0]->f_flags = O_RDONLY | (flags & O_NONBLOCK);res[1] = f;return 0;
......
}

从 get_pipe_inode 的实现,我们可以看出,匿名管道来自一个特殊的文件系统 pipefs。这个文件系统被挂载后,我们就得到了 struct vfsmount *pipe_mnt。然后挂载的文件系统的 superblock 就变成了:pipe_mnt->mnt_sb。如果你对文件系统的操作还不熟悉,要返回去复习一下文件系统那一章啊。

static struct file_system_type pipe_fs_type = {.name		= "pipefs",.mount		= pipefs_mount,.kill_sb	= kill_anon_super,
};static int __init init_pipe_fs(void)
{int err = register_filesystem(&pipe_fs_type);if (!err) {pipe_mnt = kern_mount(&pipe_fs_type);}
......
}static struct inode * get_pipe_inode(void)
{struct inode *inode = new_inode_pseudo(pipe_mnt->mnt_sb);struct pipe_inode_info *pipe;
......inode->i_ino = get_next_ino();pipe = alloc_pipe_info();
......inode->i_pipe = pipe;pipe->files = 2;pipe->readers = pipe->writers = 1;inode->i_fop = &pipefifo_fops;inode->i_state = I_DIRTY;inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;inode->i_uid = current_fsuid();inode->i_gid = current_fsgid();inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);return inode;
......
}

我们从 new_inode_pseudo 函数创建一个 inode。这里面开始填写 Inode 的成员,这里和文件系统的很像。这里值得注意的是 struct pipe_inode_info,这个结构里面有个成员是 struct pipe_buffer *bufs。我们可以知道,所谓的匿名管道,其实就是内核里面的一串缓存

另外一个需要注意的是 pipefifo_fops,将来我们对于文件描述符的操作,在内核里面都是对应这里面的操作。

const struct file_operations pipefifo_fops = {.open		= fifo_open,.llseek		= no_llseek,.read_iter	= pipe_read,.write_iter	= pipe_write,.poll		= pipe_poll,.unlocked_ioctl	= pipe_ioctl,.release	= pipe_release,.fasync		= pipe_fasync,
};

我们回到 create_pipe_files 函数,创建完了 inode,还需创建一个 dentry 和他对应。dentry 和 inode 对应好了,我们就要开始创建 struct file 对象了。先创建用于写入的,对应的操作为 pipefifo_fops;再创建读取的,对应的操作也为 pipefifo_fops。然后把 private_data 设置为 pipe_inode_info。这样从 struct file 这个层级上,就能直接操作底层的读写操作。

至此,一个匿名管道就创建成功了。如果对于 fd[1] 写入,调用的是 pipe_write,向 pipe_buffer 里面写入数据;如果对于 fd[0] 的读入,调用的是 pipe_read,也就是从 pipe_buffer 里面读取数据。

但是这个时候,两个文件描述符都是在一个进程里面的,并没有起到进程间通信的作用,怎么样才能使得管道是跨两个进程的呢?还记得创建进程调用的 fork 吗?在这里面,创建的子进程会复制父进程的 struct files_struct,在这里面 fd 的数组会复制一份,但是 fd 指向的 struct file 对于同一个文件还是只有一份,这样就做到了,两个进程各有两个 fd 指向同一个 struct file 的模式,两个进程就可以通过各自的 fd 写入和读取同一个管道文件实现跨进程通信了。

由于管道只能一端写入,另一端读出,所以上面的这种模式会造成混乱,因为父进程和子进程都可以写入,也都可以读出,通常的方法是父进程关闭读取的 fd,只保留写入的 fd,而子进程关闭写入的 fd,只保留读取的 fd,如果需要双向通行,则应该创建两个管道。

一个典型的使用管道在父子进程之间的通信代码如下: 

#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>int main(int argc, char *argv[])
{int fds[2];if (pipe(fds) == -1)perror("pipe error");pid_t pid;pid = fork();if (pid == -1)perror("fork error");if (pid == 0){close(fds[0]);char msg[] = "hello world";write(fds[1], msg, strlen(msg) + 1);close(fds[1]);exit(0);} else {close(fds[1]);char msg[128];read(fds[0], msg, 128);close(fds[0]);printf("message : %s\n", msg);return 0;}
}

 

到这里,我们仅仅解析了使用管道进行父子进程之间的通信,但是我们在 shell 里面的不是这样的。在 shell 里面运行 A|B 的时候,A 进程和 B 进程都是 shell 创建出来的子进程,A 和 B 之间不存在父子关系。

不过,有了上面父子进程之间的管道这个基础,实现 A 和 B 之间的管道就方便多了。

我们首先从 shell 创建子进程 A,然后在 shell 和 A 之间建立一个管道,其中 shell 保留读取端,A 进程保留写入端,然后 shell 再创建子进程 B。这又是一次 fork,所以,shell 里面保留的读取端的 fd 也被复制到了子进程 B 里面。这个时候,相当于 shell 和 B 都保留读取端,只要 shell 主动关闭读取端,就变成了一管道,写入端在 A 进程,读取端在 B 进程。

接下来我们要做的事情就是,将这个管道的两端和输入输出关联起来。这就要用到 dup2 系统调用了。 

int dup2(int oldfd, int newfd);

这个系统调用,将老的文件描述符赋值给新的文件描述符,让 newfd 的值和 oldfd 一样。

我们还是回忆一下,在 files_struct 里面,有这样一个表,下标是 fd,内容指向一个打开的文件 struct file。

struct files_struct {struct file __rcu * fd_array[NR_OPEN_DEFAULT];
}

在这个表里面,前三项是定下来的,其中第零项 STDIN_FILENO 表示标准输入,第一项 STDOUT_FILENO 表示标准输出,第三项 STDERR_FILENO 表示错误输出。

在 A 进程中,写入端可以做这样的操作:dup2(fd[1],STDOUT_FILENO),将 STDOUT_FILENO(也即第一项)不再指向标准输出,而是指向创建的管道文件,那么以后往标准输出写入的任何东西,都会写入管道文件。

在 B 进程中,读取端可以做这样的操作,dup2(fd[0],STDIN_FILENO),将 STDIN_FILENO 也即第零项不再指向标准输入,而是指向创建的管道文件,那么以后从标准输入读取的任何东西,都来自于管道文件。

至此,我们才将 A|B 的功能完成。

为了模拟 A|B 的情况,我们可以将前面的那一段代码,进一步修改成为下面这样:

 

#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>int main(int argc, char *argv[])
{int fds[2];if (pipe(fds) == -1)perror("pipe error");pid_t pid;pid = fork();if (pid == -1)perror("fork error");if (pid == 0){dup2(fds[1], STDOUT_FILENO);close(fds[1]);close(fds[0]);execlp("ps", "ps", "-ef", NULL);} else {dup2(fds[0], STDIN_FILENO);close(fds[0]);close(fds[1]);execlp("grep", "grep", "systemd", NULL);}return 0;
}

接下来,我们来看命名管道。我们在讲命令的时候讲过,命名管道需要事先通过命令 mkfifo,进行创建。如果是通过代码创建命名管道,也有一个函数,但是这不是一个系统调用,而是 Glibc 提供的函数。它的定义如下:

int
mkfifo (const char *path, mode_t mode)
{dev_t dev = 0;return __xmknod (_MKNOD_VER, path, mode | S_IFIFO, &dev);
}int
__xmknod (int vers, const char *path, mode_t mode, dev_t *dev)
{unsigned long long int k_dev;
....../* We must convert the value to dev_t type used by the kernel.  */k_dev = (*dev) & ((1ULL << 32) - 1);
......return INLINE_SYSCALL (mknodat, 4, AT_FDCWD, path, mode,(unsigned int) k_dev);
}

Glibc 的 mkfifo 函数会调用 mknodat 系统调用,还记得咱们学字符设备的时候,创建一个字符设备的时候,也是调用的 mknod。这里命名管道也是一个设备,因而我们也用 mknod。

SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, unsigned, dev)
{struct dentry *dentry;struct path path;unsigned int lookup_flags = 0;
......
retry:dentry = user_path_create(dfd, filename, &path, lookup_flags);
......switch (mode & S_IFMT) {
......case S_IFIFO: case S_IFSOCK:error = vfs_mknod(path.dentry->d_inode,dentry,mode,0);break;}
......
}

对于 mknod 的解析,我们在字符设备那一节已经解析过了,先是通过 user_path_create 对于这个管道文件创建一个 dentry,然后因为是 S_IFIFO,所以调用 vfs_mknod。由于这个管道文件是创建在一个普通文件系统上的,假设是在 ext4 文件上,于是 vfs_mknod 会调用 ext4_dir_inode_operations 的 mknod,也即会调用 ext4_mknod。

const struct inode_operations ext4_dir_inode_operations = {
.......mknod		= ext4_mknod,
......
};static int ext4_mknod(struct inode *dir, struct dentry *dentry,umode_t mode, dev_t rdev)
{handle_t *handle;struct inode *inode;
......inode = ext4_new_inode_start_handle(dir, mode, &dentry->d_name, 0,NULL, EXT4_HT_DIR, credits);handle = ext4_journal_current_handle();if (!IS_ERR(inode)) {init_special_inode(inode, inode->i_mode, rdev);inode->i_op = &ext4_special_inode_operations;err = ext4_add_nondir(handle, dentry, inode);if (!err && IS_DIRSYNC(dir))ext4_handle_sync(handle);}if (handle)ext4_journal_stop(handle);
......
}#define ext4_new_inode_start_handle(dir, mode, qstr, goal, owner, \type, nblocks)		    \__ext4_new_inode(NULL, (dir), (mode), (qstr), (goal), (owner), \0, (type), __LINE__, (nblocks))void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev)
{inode->i_mode = mode;if (S_ISCHR(mode)) {inode->i_fop = &def_chr_fops;inode->i_rdev = rdev;} else if (S_ISBLK(mode)) {inode->i_fop = &def_blk_fops;inode->i_rdev = rdev;} else if (S_ISFIFO(mode))inode->i_fop = &pipefifo_fops;else if (S_ISSOCK(mode));	/* leave it no_open_fops */else
......
}

在 ext4_mknod 中,ext4_new_inode_start_handle 会调用 __ext4_new_inode,在 ext4 文件系统上真的创建一个文件,但是会调用 init_special_inode,创建一个内存中特殊的 inode,这个函数我们在字符设备文件中也遇到过,只不过当时 inode 的 i_fop 指向的是 def_chr_fops,这次换成管道文件了,inode 的 i_fop 变成指向 pipefifo_fops,这一点和匿名管道是一样的。

这样,管道文件就创建完毕了。

接下来,要打开这个管道文件,我们还是会调用文件系统的 open 函数。还是沿着文件系统的调用方式,一路调用到 pipefifo_fops 的 open 函数,也就是 fifo_open。

static int fifo_open(struct inode *inode, struct file *filp)
{struct pipe_inode_info *pipe;bool is_pipe = inode->i_sb->s_magic == PIPEFS_MAGIC;int ret;filp->f_version = 0;if (inode->i_pipe) {pipe = inode->i_pipe;pipe->files++;} else {pipe = alloc_pipe_info();pipe->files = 1;inode->i_pipe = pipe;spin_unlock(&inode->i_lock);}filp->private_data = pipe;filp->f_mode &= (FMODE_READ | FMODE_WRITE);switch (filp->f_mode) {case FMODE_READ:pipe->r_counter++;if (pipe->readers++ == 0)wake_up_partner(pipe);if (!is_pipe && !pipe->writers) {if ((filp->f_flags & O_NONBLOCK)) {filp->f_version = pipe->w_counter;} else {if (wait_for_partner(pipe, &pipe->w_counter))goto err_rd;}}break;case FMODE_WRITE:pipe->w_counter++;if (!pipe->writers++)wake_up_partner(pipe);if (!is_pipe && !pipe->readers) {if (wait_for_partner(pipe, &pipe->r_counter))goto err_wr;}break;case FMODE_READ | FMODE_WRITE:pipe->readers++;pipe->writers++;pipe->r_counter++;pipe->w_counter++;if (pipe->readers == 1 || pipe->writers == 1)wake_up_partner(pipe);break;
......}
......
}

在 fifo_open 里面,创建 pipe_inode_info,这一点和匿名管道也是一样的。这个结构里面有个成员是 struct pipe_buffer *bufs。我们可以知道,所谓的命名管道,其实是也是内核里面的一串缓存。

接下来,对于命名管道的写入,我们还是会调用 pipefifo_fops 的 pipe_write 函数,向 pipe_buffer 里面写入数据。对于命名管道的读入,我们还是会调用 pipefifo_fops 的 pipe_read,也就是从 pipe_buffer 里面读取数据。

总结时刻

无论是匿名管道,还是命名管道,在内核都是一个文件。只要是文件就要有一个 inode。这里我们又用到了特殊 inode、字符设备、块设备,其实都是这种特殊的 inode。

在这种特殊的 inode 里面,file_operations 指向管道特殊的 pipefifo_fops,这个 inode 对应内存里面的缓存。

当我们用文件的 open 函数打开这个管道设备文件的时候,会调用 pipefifo_fops 里面的方法创建 struct file 结构,他的 inode 指向特殊的 inode,也对应内存里面的缓存,file_operations 也指向管道特殊的 pipefifo_fops。

写入一个 pipe 就是从 struct file 结构找到缓存写入,读取一个 pipe 就是从 struct file 结构找到缓存读出。

课堂练习

上面创建匿名管道的程序,你一定要运行一下,然后试着通过 strace 查看自己写的程序的系统调用,以及直接在命令行使用匿名管道的系统调用,做一个比较。

 

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

相关文章

  1. Navicat通过HTTP通道连接数据库

    Background 由于内网安全限制&#xff0c;或者网关限制&#xff0c;Navicat应用在本地无法常规地建立连接&#xff0c;访问远程数据库。 Premise 安装Navicat系列工具Mac OSLNMP架构服务器 Process HTTP通道脚本目录&#xff1a; /Applications/Navicat Premium.app/Cont…...

    2024/4/15 6:11:17
  2. SpringBoot 集成Swagger3,spring-plugin-core提示不匹配

    今天使用SpringBoot集成Swagger 输出如下错误信息: *************************** APPLICATION FAILED TO START ***************************Description:An attempt was made to call the method org.springframework.plugin.core.PluginRegistry.getPluginFor(Ljava/lang/Ob…...

    2024/4/20 22:29:23
  3. java之final--Java笔记

    目录 final 1.可以修饰类、属性、方法&#xff08;不能修饰构造方法即构造器&#xff09;、局部变量 ​ 2.final修饰的属性最好用XX_XX来命名 ​ 3.当不希望类被继承时、不希望类的某个属性的值被修改时、不希望某个局部变量被修改时&#xff0c;可以用final修饰 ​ ​ ​…...

    2024/4/20 16:26:05
  4. 实战 | 基于敏捷模式的分层自动化测试体系建设与应用

    随着敏捷开发模式在IT领域有越来越广泛和深入的应用&#xff0c;测试团队也被要求能适应快速迭代、快速响应的敏捷开发模式&#xff0c;实现研发全过程和上下游团队的高效协作。为适应敏捷开发模式&#xff0c;德邦证券于2018年开始构建DevOps体系&#xff0c;并配套研发了DevO…...

    2024/4/15 6:11:22
  5. 复盘字节跳动 | 番茄小说三面经历,被盘问35个硬核技术,offer审批中

    字节番茄小说一面 2021/9/24 约1h 1. 自我介绍 2. 项目相关 3. Java中常用的集合类 (先说Collection和Map接口&#xff0c;再分别说子接口和实现类&#xff0c;以及大概的区别&#xff0c;没让细讲源码) 4. 有一组数据&#xff0c;需要按照顺序对它进行加密&#xff0c;如果…...

    2024/4/19 10:13:26
  6. #10047. 「一本通 2.2 练习 3」似乎在梦中见过的样子

    题目链接&#xff1a;似乎在梦中见过的样子 int main() {scanf("%s",a1);int lstrlen(a1);scanf("%d",&k);for(int i1;i<l-k;i){printf("%s**\n",ai-1);//kmp(ai-1);} // printf("%d\n",sum);//kmp(si-1); }下面这个图为输出结…...

    2024/4/23 18:14:16
  7. Docker 网络

    1. 启动一个tomcat容器 docker run -d -p 8080 --name tomcat01 tomcat 2. 查看容器ip, 看到 eth0if5 网卡 docker exec -it tomcat01 ip addr --------------------------------------------------------------------------------------------- 4: eth0if5: <BROADCAST,MUL…...

    2024/4/15 6:11:17
  8. 【Golang】微服务实现工具 -- go-kit 易懂

    go-kit是一个分布式的开发工具集&#xff0c;在大型的组织&#xff08;业务&#xff09;中可以用来构建微服务&#xff0c;其解决了分布式系统中大多数常见问题&#xff0c;因此&#xff0c;使用者可以将精力集中在业务逻辑上 首先我们要明白&#xff0c;go-kit不是一个框架&am…...

    2024/4/15 6:10:52
  9. 一起学深度学习系列——线性回归

    动手学线性回归线性回归手撕[^1]构造数据集线性回归基于PyTorch实现python知识点补充python 的 迭代器描述iter()next()python 的 生成器描述线性回归手撕[^1] %matplotlib inline import random import torch from d2l import torch as d2l构造数据集 yXwbϵw[2,−3.4]Tb4.2…...

    2024/4/17 15:06:51
  10. MFC单文档点击菜单弹出对话框

    1. 资源文件dialog文件夹内添加一个新的dialog 2. 新dialog处右键点击类向导&#xff0c;新建对话框类 3. 在菜单对应的选项处&#xff0c;右键添加事件处理程序&#xff0c;选择View类 4. 在对应处编辑代码: dialog dig; dig.DoModal();...

    2024/4/19 1:02:54
  11. JavaScript 防止崩溃的可选链

    在开发过程中需要拿到一个嵌套比较深的属性的值&#xff0c;需要做很多的判断&#xff0c;例如&#xff1a; const obj {name: "xiaoming",age: 27,address: {province: {city: hangzhou}} }要拿到 obj 对象中 city 属性的值&#xff0c;需要判断 4 次看每一层是否…...

    2024/4/18 1:49:23
  12. CF 1603C(Extreme Extension-数学)

    给定一个正整数序列aia_iai​。每次操作可以把一个数aaa拆成b,a−bb,a-bb,a−b两个正整数放回原位置 一个序列的 extreme values 定义为将一个序列变为不降序列的最小操作步数。 你希望求出所有子串的 extreme values 的和。 序列长度n≤105,ai≤105n \le 10^5,a_i \le 10^5n≤…...

    2024/4/20 22:31:15
  13. 日记:软件测试从入门到入土

    移动端项目测试 相对其他来说更容易理解 加油&#xff0c;争取早日入土...

    2024/4/15 6:11:42
  14. 垂直同步细说

    垂直消隐间隔VBlank&#xff08;vertical blanking interval&#xff09; 在将光信号转换为电信号的扫描过程中&#xff0c;扫描总是从图像的左上角开始&#xff0c;水平向前行进&#xff0c;同时扫描点也以较慢的速率向下移动。当扫描点到达图像右侧边缘时&#xff0c;扫描点…...

    2024/4/22 14:39:45
  15. 30.package和import

    关于java语言中的包机制&#xff1a; 包有称为package&#xff0c;java中引入包机制主要是为了方便程序的管理&#xff0c;我们可以将不同的功能的类放在不同的软件包下&#xff0c;方便查找与管理。 关于package的定义&#xff1a; 在java源程序的第一行编写package语句&…...

    2024/4/15 6:11:52
  16. 自用的图标

    ...

    2024/4/19 15:09:38
  17. 计算机网络之物理层篇

    文章目录1. 物理层的基本概念2. 物理层下面的传输媒体3. 主要的传输方式4. 编码与调制5. 信道的极限容量6. 信道复用技术1. 物理层的基本概念 &#xff08;1&#xff09;、什么是物理层&#xff1f; 物理层考虑的是怎样才能在连接各种计算机的传输媒体上传输数据比特流物理层为…...

    2024/4/20 15:45:43
  18. Spring Security---自动登录二次校验和持久化令牌

    形成天才的决定因素应该是勤奋。—— 郭沫若 文章目录二次校验配置&#xff1a;持久化令牌配置&#xff1a;Spring Security为用户提供了方便的记住密码功能&#xff0c;将生成的rememberMeToken放入了cookie中&#xff0c;这也意味着只要token没有过期&#xff0c;一旦泄漏后就…...

    2024/4/20 19:07:21
  19. mysql基本操作(一):数据库、建表约束

    MySQL操作 一、数据库操作 操作名指令备注登录数据库sudo mysql -uroot创建数据库CREATE DATABASE dbnamedbname是自定义名字查看当前服务器所有数据库SHOW DATABASES使用数据库USE dbnamedbname是自定义名字删除数据库DROP DATABASE databasenamedbname是自定义名字修改数据…...

    2024/4/15 6:12:02
  20. pytorch 误区

    num_oov max(torch.max(ext_src_seq - self.vocab_size 1), 0) 误区解读&#xff1a; ext_src_seq&#xff1a; [batch_size&#xff0c; sequence_len] self.vocab_size: 50000 ext_src_seq - self.vocab_size 1&#xff1a;这种运算实际上是对ext_src_seq中的每个元素…...

    2024/4/15 6:11:52

最新文章

  1. uinapp 开发环境和生产环境

    uni-app 可通过 process.env.NODE_ENV 判断当前环境是开发环境还是生产环境。一般用于连接测试服务器或生产服务器的动态切换。 在 HBuilderX 中&#xff0c;点击“运行”编译出来的代码是开发环境&#xff0c;点击“发行”编译出来的代码是生产环境cli 模式下&#xff0c;是通…...

    2024/4/23 22:35:31
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 【LeetCode热题100】【二叉树】二叉树的中序遍历

    题目链接&#xff1a;94. 二叉树的中序遍历 - 力扣&#xff08;LeetCode&#xff09; 中序遍历就是先遍历左子树再遍历根最后遍历右子树 class Solution { public:void traverse(TreeNode *root) {if (!root)return;traverse(root->left);ans.push_back(root->val);tra…...

    2024/4/23 6:15:26
  4. Java深度优先搜索DFS(含面试大厂题和源码)

    深度优先搜索&#xff08;Depth-First Search&#xff0c;简称DFS&#xff09;是一种用于遍历或搜索树或图的算法。DFS 通过沿着树的深度来遍历节点&#xff0c;尽可能深地搜索树的分支。当节点v的所在边都已被探寻过&#xff0c;搜索将回溯到发现节点v的那条边的起始节点。这个…...

    2024/4/23 6:13:06
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/23 20:58:27
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/23 13:30:22
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/23 13:28:06
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/20 23:26:47
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/23 13:27:44
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/19 11:57:53
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/23 13:29:53
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/23 13:27:22
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/23 13:28:42
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/23 22:01:21
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/23 13:29:23
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/23 13:27:46
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/23 13:47:22
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/19 11:59:23
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/4/19 11:59:44
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/23 13:28:08
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/23 13:29:47
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/23 13:28:14
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/23 13:27:51
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/23 13:27:19
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57