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

自定义minshell

我们在前面已经了解了进程的概念,以及如何进行进程控制。接下来我们就使用这些知识,来自己实现一个shell即命令行解释器!!!

一.打印命令行提示符

我们在使用Linux操作系统时,一登陆就会启动bash进程——命令行解释器,而bash则会先打印一串字符串,用来提醒用户当前的一些信息。这里面包括了用户名,主机名,当前的工作目录等等

所以我们的首要任务就是打印一个命令行,内容就是上面这些。而这些信息都存储在bash的环境变量中

我们可以将打印命令行提示符封装成一个函数:首先就是命令行的格式,我们可以用宏来表示。接着就是使用getenv来获取指定环境变量的内容,然后按照指定格式打印即可

#define FORMAT "[%s@%s %s]# " // 命令行提示符格式
const size_t COMMAND_SIZE = 1024; // 命令行提示符的最大长度// 获取用户名
char* getUserName()
{return getenv("USER");
}// 获取主机名
char* getHostName()
{return getenv("HOSTNAME");
}// 获取当前工作目录
char* getPwd()
{return getenv("PWD");
}// 制作命令行提示符
void makeCommandLine(char* prompt, size_t size)
{snprintf(prompt, size, FORMAT, getUserName(), getHostName(),getPwd());
}// 打印命令行提示符
void printCommandLinePrompt()
{char prompt[COMMAND_SIZE];makeCommandLine(prompt, sizeof(prompt));    printf("%s",prompt);fflush(stdout);
}

我们先来看一下结果:

虽然我们打印出了命令行提示符,但是却又一些问题:

  • shell中的命令行提示符只打印当前工作目录,而我们的shell却打印出了当前工作目录的绝对路径
  • shell进程应该是常驻内存的,启动我们自己的shell之后,应该是看不到系统shell的,接下来就是等待用户输入了!!

对于第一点,我们可以再封装一个函数,只取出当前目录!!!

我们在制作命令行提示符时,就调用下面这个函数

// 只取出工作目录
std::string getPwdName()
{std::string pwd_name = getPwd();size_t pos = pwd_name.rfind('/');return pwd_name.substr(pos+1, std::string::npos);
}

启动myshell之后,等待用户输入其实就是让shell阻塞在那里了,这不就是scanf/cin么?所以我们可以先下一个scanf来看看现象:

我们看,成功解决了上面的问题。接下来我们要处理的就是命令行输入的问题了。

二.获取用户输入的命令 

// 获取用户输入
bool getUserCommand(char* cmd, int size)
{const char* ans = fgets(cmd, size, stdin); if(ans == NULL) return false;cmd[strlen(cmd) - 1] = '\0';return true;
}int main()
{printCommandLinePrompt();char command[COMMANDSIZE];getUserCommand(command, sizeof(command));return 0;
}

我们虽然借助上面可以获取用户输入的字符,先不管如何解析和执行该命令,输入完命令之后,假设执行完了,打印的应该还是我们自己的shell,但结果却不是

因为shell是常驻内存的程序,所以本质上应该是个死循环!!! 所以我们shell的逻辑都应该在该while循环中执行!!!

int main()
{while(1){printCommandLinePrompt();char command[COMMANDSIZE];getUserCommand(command, sizeof(command));}return 0;
}

另外,我们借助fgets获取字符,它以回车作为分隔符。但是如果我们只敲了回车,command里面是个空串,没必要进行后续的命令分析...所以我们在这里进行判断,如果返回false,则contine,重新输入命令,如果为true,才执行下面的逻辑

char command[COMMANDSIZE];
if(!getUserCommand(command, sizeof(command)))continue;

三.切割命令,做命令分析

我们输入的命令中间可能会含有空格比如 “ ls -l -al”,我们需要对命令进行切割,以空格为分隔符,将命令拆分成多部份,放入到命令行参数表中!!!

以空格作为分割符来切割命令,我们可以使用strtok函数来实现。

// 命令行参数表
const size_t MAXARGC = 128;
char* argv[MAXARGC];
int argc = 0;// 切割命令,对命令进行分析
void commandParse(char* cmd)
{argc = 0;argv[argc++] = strtok(cmd, " ");while(NULL != (argv[argc++] = strtok(NULL, " "))) ;argc--;
}

当使用strtok想继续对一个字符串继续切割时,第一个参数要传NULL。

这样写不仅切割了命令,而且还给命令行参数表最后放了一个NULL作为结尾。完美契合我们的目标!!!

我们先运行一下当前程序,并打印参数表,看看是否正确。

四.执行命令

我们拿到了命令行参数之后,接下来就是去执行命令。

我们在进程控制部分了解到了进程切换,而且我们也知道所有的进程都是bash的子进程。

所以我们执行命令的逻辑就是让shell创建子进程,让子进程去执行我们分析出来的命令。

// 执行命令
void exectue()
{pid_t id = fork();if(id == 0){//  childexecvp(argv[0], argv);exit(1);}// fatherint status = 0;pid_t rid = waitpid(id, &status, 0); // 阻塞等待if(rid < 0){exit(2);}
}

我们这里之所以选择execvp,是因为我们在处理的时候就已经拿到了命令行参数表,用这个最方便。

到现在,我们的minshell整体逻辑已经完成的差不多了,现在看一下运行的情况:

但是目前的minshell是有问题的,当我们执行cd命令时,我们当前的工作目录是不会改变的 

这是因为cd作为内建命令,是由bash进程自己亲自执行的,而我们的cd是用子进程执行的,所以子进程的工作目录改变了,但shell并没有。

因此,我们在执行命令之前需要都命令进行分类——内建命令和其他命令。其他命令就去让子进程执行,而内建命令我们需要让shell自己执行!!!

五.执行内建命令

内建命令有好几个,这里我们以cd命令为例来做演示。

我们在分割命令之后,接着就是对第一个命令行参数的第一个参数进行分析,如果是cd等内建命令则用shell自己执行,反之让子进程执行。

如果一个命令是内建命令,他被shell执行之后,就不应该在被子进程执行了,所以直接continue。

// 执行内建命令
bool checkAndExectueBulidIn()
{std::string cmd = argv[0];if(cmd == "cd"){CD();return true;}else if(cmd == "echo"){return true;}return false;
}int main()if(checkAndExectueBulidIn())continue;

接下里就是执行cd命令的逻辑了:

我们可以使用chdir系统调用来改变当前的工作目录。因为对于cd命令有很多快捷方式,这里我们只实现一些。

// cd命令
void CD()
{if(argc == 1){chdir(getenv("HOME"));}else{std::string where = argv[1];if(where == "~"){chdir(getenv("HOME"));}else if(where == "-"){// todo}else{chdir(argv[1]);}}
}

看结果:

我们使用cd命令之后,发现命令行提示符处的当前目录并没有改变,但是我们通过pwd来查看当前工作目录却发现目录已经改变了。这是为啥呢? 

我们自己的shell的环境变量都是继承自父进程,也就是bash。而我们打印命令行提示符使用的是环境变量PWD,可环境变量在运行中一直都没有改变,所以导致我们每一次打印命令行提示符时不会改变。

为了解决这个问题,我们可以使用getcwd来获取跳转之后的目录,并将环境变量PWD进行修改,此时就可以达到路径改变的同时命令行提示符也发生改变!

// 当前工作目录
char pwd[MAXARGC];
char pwdenv[MAXARGC];// 获取当前工作目录
char* getPwd()
{char* s = getcwd(pwd, sizeof(pwd));if(s != NULL){snprintf(pwdenv, sizeof(pwdenv), "PWD=%s", pwd);putenv(pwdenv); // 更新环境变量}return getenv("PWD");
}// 只取出工作目录
std::string getPwdName()
{std::string pwd_name = getPwd();if(pwd_name.size() == 1) return pwd_name;size_t pos = pwd_name.rfind('/');return pwd_name.substr(pos+1, std::string::npos);
}

修改之后,命令行提示符处的信息就与当前的工作目录同步了。 

 除了cd ~外,我们还可以使用cd - ,快速切换到上一次所在的工作目录。

想要实现cd -,我们就得知道上一次的工作目录是存在环境变量OLDPWD中的。我们每次在执行cd命令时,oldpwd和pwd都会进行变化。所以我们在每次cd前,先将当前所在目录赋值给oldpwd,并putenv更新,然后再cd到指定目录,而每次执行完一个指令之后,打印命令行提示符时会更新pwd,所以不用管。

但是对于cd -来说,我们得先跳转到oldpwd,

// 更新上一次的工作目录
void reOldPwd()
{snprintf(oldpwdenv, sizeof(pwdenv), "OLDPWD=%s", getenv("PWD"));putenv(oldpwdenv);
}// cd命令
void CD()
{if(argc == 1){reOldPwd();chdir(getenv("HOME"));}else{std::string where = argv[1];if(where == "~"){reOldPwd();chdir(getenv("HOME"));}else if(where == "-"){chdir(getenv("OLDPWD"));reOldPwd();}else{reOldPwd();chdir(argv[1]);}}
}

再更新它。如果先更新oldpwd的话,此时pwd和oldpwd都指向当前目录,会导致跳转失败。

其他的内建命令待做......

六.环境变量

当登录用户后,bash进程就会启动,它会从配置文件中读取环境变量加载到bash内部。但是我们自己实现的minshell没有办法读取文件。所以这里我们选择读取父进程的环境变量以达到模拟从配置文件中读取环境变量的过程。

// 环境变量表
char* env[MAXARGC];
int envs = 0;// 初始化环境变量
void InitEnviron()
{// 模拟从配置文件读取环境变量extern char** environ;for(int i=0; environ[i]; ++i){env[i] = (char*)malloc(strlen(environ[i]));strcpy(env[i], environ[i]);envs++;}env[envs] = NULL;// 将环境变量加载到进程内部for(int i=0; env[i]; i++){putenv(env[i]);}// 让全局的环境变量指针指向自己的环境变量表environ = env;
}

这下我们就有了自己的环境变量表了。


以上,就是一个简单的minshell,后面学到新知识后,在对其进行扩充。

相关文章:

自定义minshell

我们在前面已经了解了进程的概念&#xff0c;以及如何进行进程控制。接下来我们就使用这些知识&#xff0c;来自己实现一个shell即命令行解释器&#xff01;&#xff01;&#xff01; 一.打印命令行提示符 我们在使用Linux操作系统时&#xff0c;一登陆就会启动bash进程——命…...

坦克大战(c++)

今天我给大家分享一个c游戏。 废话不多说&#xff0c;作品展示&#xff1a; #include <stdio.h> #include <windows.h> #include <time.h> //里规格&#xff1a;长39*278 &#xff08;真坐标&#xff09;(假坐标宽为39) 高39 //外规格&#xff1a;长…...

《可爱风格 2048 游戏项目:HTML 实现全解析》

一、引言 在如今的数字化时代&#xff0c;小游戏以其简单易上手、趣味性强的特点深受大家喜爱。2048 游戏作为一款经典的数字合并游戏&#xff0c;拥有庞大的玩家群体。本文将详细介绍一个用单文件 HTML 实现的可爱风格 2048 游戏项目&#xff0c;它不仅具备传统 2048 游戏的基…...

C++ 利用类模板实现一个数组类封装

案例描述&#xff1a; 实现一个通用的数组类&#xff0c;要求如下&#xff1a; 可以对内置数据类型以及自定义数据类型的数据进行存储 将数组中的数据存储到堆区 构造函数中可以传入数组的容量 提供对应的拷贝构造函数以及operator防止浅拷贝问题 提供尾插法和尾删法对数组…...

【AndroidRTC-11】如何理解webrtc的Source、TrackSink

Android-RTC系列软重启&#xff0c;改变以往细读源代码的方式 改为 带上实际问题分析代码。增加实用性&#xff0c;方便形成肌肉记忆。同时不分种类、不分难易程度&#xff0c;在线征集问题切入点。 问题1&#xff1a;如何理解VideoSource、VideoTrack&VideoSink三者的关系…...

数据类设计_图片类设计之9_图标类设计_C++实战_(前端架构)

前言 学的东西多了,要想办法用出来.C和C是偏向底层的语言,直接与数据打交道.尝试做一些和数据方面相关的内容 引入 前面写了矩阵图形类对象和像素图形类对象,本贴通过一个快捷方式图标类的设计,来继续数据类型设计的一些讨论. 快捷方式图标是这个样子: 属性分析 首先,快捷方式…...

fuse性能关键参数entry_timeout

entry_timeout 是 FUSE&#xff08;Filesystem in Userspace&#xff09;中的一个选项&#xff0c;用于控制目录项缓存的有效期。具体来说&#xff0c;它决定了文件系统在多长时间内缓存目录项&#xff08;如文件名到 inode 的映射&#xff09;&#xff0c;从而影响文件系统的性…...

3. 轴指令(omron 机器自动化控制器)——>MC_ResetFollowingError

机器自动化控制器——第三章 轴指令 13 MC_ResetFollowingError变量▶输入变量▶输出变量▶输入输出变量 功能说明▶指令详情▶时序图▶重启动运动指令▶多重启运动指令▶异常 MC_ResetFollowingError 对指令当前位置和反馈当前位置的偏差进行复位。 指令名称FB/FUN图形表现S…...

Spring Boot项目快速创建-开发流程(笔记)

主要流程&#xff1a; 前端发送网络请求->controller->调用service->操纵mapper->操作数据库->对entity数据对象赋值->返回前端 前期准备&#xff1a; maven、mysql下载好 跟学视频&#xff0c;感谢老师&#xff1a; https://www.bilibili.com/video/BV1gm4…...

[操作系统] 进程间通信:进程池的实现

引言 在学习操作系统时&#xff0c;进程间通信&#xff08;IPC&#xff09;和多进程管理是核心内容之一。进程池是一种常见的模式&#xff0c;通过预先创建一组工作进程来处理任务&#xff0c;避免频繁创建和销毁进程带来的开销。本文将详细剖析一个用 C 实现的进程池代码&…...

信号相关的程序

1、不断打印*换行之后响应信号&#xff0c;然后循环 #include <stdio.h> #include <string.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> static void alrm_handler(int signo) {write(1,"!",1); }int main( in…...

【计算机网络】-计算机网络期末复习题复习资料

一、计算机网络体系结构&#xff08;800字&#xff09; 1. OSI参考模型 七层结构&#xff1a;物理层→数据链路层→网络层→传输层→会话层→表示层→应用层 各层核心功能&#xff1a; 物理层&#xff1a;比特流传输&#xff08;如RJ45、光纤接口&#xff09; 数据链路层&…...

Linux 基础入门操作 第十二章 TINY Web 服务器

1 服务器基础架构 1.1 背景知识 Web 服务器使用 HTTP 协议与客户端&#xff08;即浏览器&#xff09;通信&#xff0c;而 HTTP 协议又基于 TCP/IP 协议。因此我们要做的工作就是利用 Linux 系统提供的 TCP 通信接口来实现 HTTP 协议。 而 Linux 为我们提供了哪些网络编程接口…...

L2-052 吉利矩阵

L2-052 吉利矩阵 - 团体程序设计天梯赛-练习集 这道题打表 打表部分被注释了 n4 [0,0,282, 2008, 10147, 40176, 132724, 381424, 981541, 2309384] n3 [0,0,21, 55, 120, 231, 406, 666, 1035, 1540] n2 [0,0,3, 4, 5, 6, 7, 8, 9, 10] l,n map(int,input().split()) if…...

BKA-CNN-LSTM、CNN-LSTM、LSTM、CNN四模型多变量时序光伏功率预测,附模型研究报告

BKA-CNN-LSTM、CNN-LSTM、LSTM、CNN四模型多变量时序光伏功率预测&#xff0c;附模型研究报告 目录 BKA-CNN-LSTM、CNN-LSTM、LSTM、CNN四模型多变量时序光伏功率预测&#xff0c;附模型研究报告预测效果基本介绍程序设计参考资料 预测效果 基本介绍 BKA-CNN-LSTM、CNN-LSTM、…...

【读书笔记】华为《从偶然到必然》

note 华为的成功并非偶然&#xff0c;而是通过IPD体系、投资组合管理、平台战略等系统性工具&#xff0c;将研发投资转化为可持续的商业竞争力。书中强调的“管理即内部因素”理念&#xff0c;揭示了企业规模扩张与管理能力匹配的深层规律&#xff0c;为高科技企业提供了可借鉴…...

flink广播算子Broadcast

文章目录 一、Broadcast二、代码示例三.或者第二种(只读取一个csv文件到广播内存中)提示:以下是本篇文章正文内容,下面案例可供参考 一、Broadcast 为了关联一个非广播流(keyed 或者 non-keyed)与一个广播流(BroadcastStream),我们可以调用非广播流的方法 connect(),…...

实时图像处理:让你的应用更智能

I. 引言 实时图像处理在现代应用中扮演着重要的角色&#xff0c;它能够使应用更加智能、响应更加迅速。本文将深入探讨实时图像处理的原理、部署过程以及未来的发展趋势&#xff0c;旨在帮助开发者更好地理解如何将实时图像处理应用于他们的项目中。 II. 实时图像处理的基础概…...

深入理解 Linux 基础 IO:从文件操作到缓冲区机制

亲爱的读者朋友们&#x1f603;&#xff0c;此文开启知识盛宴与思想碰撞&#x1f389;。 快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 在 Linux 系统中&#xff0c;文件输入输出&#xff08;IO&#xff09;…...

汇编语言高级编程技巧:从基础到进阶

前言 汇编语言作为底层编程语言&#xff0c;直接操作硬件&#xff0c;执行效率高&#xff0c;但编写复杂逻辑时往往显得繁琐。通过使用汇编伪指令和宏&#xff0c;我们可以实现类似于高级语言的结构&#xff0c;如条件判断、循环、结构体和函数等&#xff0c;从而提升代码的可读…...

Android Studio常见问题解决

一、环境配置问题 1. 安装失败 问题描述&#xff1a;在安装过程中&#xff0c;可能会遇到硬件要求不符合、网络问题、安装包损坏、权限不足或安装路径问题等&#xff0c;导致安装失败。 解决方法&#xff1a; 硬件要求&#xff1a;确保设备满足最低硬件要求。 网络问题&…...

【RHCE】LVS-NAT模式负载均衡实验

目录 题目 IP规划 配置IP RS1 RS2 RS3 LVS client 配置RS 配置LVS 安装lvs软件 启动ipvsadm服务 lvs规则匹配 ipvsadm部分选项 客户端测试 总结 题目 使用LVS的 NAT 模式实现 3 台RS的轮询访问&#xff0c;IP地址和主机自己规划。 IP规划 主机IP地址RS1-nat模…...

MacOS下的IntelliJ IDEA突然无法访问本机的虚拟机

今天在开发的过程中&#xff0c;突然遇到一个怪事&#xff0c;之前运行的好好的程序&#xff0c;突然间报无法连接redis服务器&#xff0c;一开始以为是网络问题&#xff0c;在OS的terminal里又是ping 又是telnet的&#xff0c;一切正常&#xff0c;可是程序就是连不上。 挠了半…...

【渗透测试】Fastjson 反序列化漏洞原理(一)

目录 一、Fastjson 是什么二、Fastjson 工作原理三、反序列化漏洞原理1. 反序列化漏洞的定义2. Fastjson 的反序列化机制3. 漏洞成因关注以下几点(1) 动态类型解析(2) 自动调用方法(3) 信任用户输入 4. 漏洞利用过程(1) 寻找可利用的类&#xff08;也称为 "Gadget"&a…...

BM100-K系列开关量输入信号隔离器

1. 产品概述 BM100-K系列开关量输入信号隔离器是一款高性能的信号处理设备&#xff0c;专为工业自动化控制系统设计。该产品支持干接点或NAMUR型接近开关输入&#xff0c;并通过继电器或晶体管实现隔离输出。其核心功能包括输入输出逻辑控制&#xff08;同相/反相可调&#xf…...

c++11 | 细说智能指针

&#x1f493;个人主页&#xff1a;mooridy &#x1f493;专栏地址&#xff1a;C 关注我&#x1f339;&#xff0c;和我一起学习更多计算机的知识 &#x1f51d;&#x1f51d;&#x1f51d; 什么是智能指针&#xff1f; 智能指针是 C 中一种用于管理动态内存的机制。它提供了一…...

谷歌大型推理模型曝光!击败Claude-3.7-Thinking

哎&#xff01;最近推特上的网友在LMSYS Arena 发现了个泄漏的大模型 Nebula&#xff0c;效果据说特别好&#xff0c;打败了o1、o3-mini、Claude 3.7 Thinking等模型&#xff1a; 网友们通过询问和分析 API&#xff0c;发现这似乎是谷歌正在秘密测试的新推理模型&#xff01;推…...

Python FastAPI面试题及参考答案

目录 FastAPI 的优缺点是什么?列举典型应用场景。 解释 FastAPI 的路由机制,如何定义路径参数和查询参数? Pydantic 模型在 FastAPI 中的作用是什么?如何进行数据验证与序列化? FastAPI 如何自动生成 OpenAPI 文档?Swagger UI 和 ReDoc 的区别? 什么是 ASGI?FastAP…...

C++(初阶)(八)——string

string string遍历下标[]迭代器iterator反向迭代器 范围for修改 Capacitysize和lengthmax_sizecapacityclearcapacity的扩容reserveresize Element accessoperator[]和at **Modifiers**:appendinserterasereplace String operationsc_strsubstr和findfind_first_ofgetline 题目…...

计算机操作系统处理机调度(1)

系列文章目录 第三章&#xff1a;处理机调度与死锁 文章目录 系列文章目录前言一、作业和资源&#xff1a;二、处理机调度的层次&#xff1a; 1.高级调度2.初级调度3.中级调度 三、作业调度算法举例&#xff1a;总结 前言 在多道程序的环境下&#xff0c;内存中存在着多个进…...

ctfshow REVERSE re2 萌新赛 内部赛 七夕杯 WP

目录 re2 萌新赛 flag白给 签退 数学不及格 内部赛 批量生产的伪劣产品 来一个派森 好好学习 天天向上 屏幕裂开了 七夕杯 逆向签到 easy_magic re2 ida分析主函数&#xff0c;将flag.txt内容加密写入enflag.txt 这是密钥加密过程 标准rc4加密 简单异或解…...

云服务器怎么设置端口禁用呢?

在云服务器上禁用特定端口是提升安全性的重要措施&#xff0c;可通过云平台安全组和服务器本地防火墙双重配置实现。以下是详细操作指南&#xff1a; 一、通过云平台安全组禁用端口&#xff08;优先推荐&#xff09; 1. 莱卡云/腾讯云/华为云等操作步骤 登录云控制台 进入ECS实…...

V8引擎源码编译踩坑实录

背景 为了解决 view8 代码没有指定版本的 v8 引擎问题GitHub - suleram/View8: View8 - Decompiles serialized V8 objects back into high-level readable code. 但是打出来了exe文件也没啥用&#xff0c;不清楚这个view8是解决啥逆向用的&#xff0c;如果想逆向electron的j…...

享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享技术来高效地支持大量细粒度对象的复用。 一、基础 1 意图 运用共享技术有效地支持大量细粒度的对象 减少内存中对象的数量,节省系统资源 2 适用场景 一个应用程序使用了大量对象 由于对象数量庞大造成很大的…...

RAG(Retrieval-Augmented Generation)基建之PDF解析的“魔法”与“陷阱”

嘿&#xff0c;亲爱的算法工程师们&#xff01;今天咱们聊一聊PDF解析的那些事儿&#xff0c;简直就像是在玩一场“信息捉迷藏”游戏&#xff01;PDF文档就像是个调皮的小精灵&#xff0c;表面上看起来规规矩矩&#xff0c;但当你想要从它那里提取信息时&#xff0c;它就开始跟…...

搭建小程序该如何选择服务器?

当企业选择开发属于自己的小程序&#xff0c;则需要服务器的支持&#xff0c;服务器可以帮助加速小程序的上线速度&#xff0c;影响小程序后面的运行是否流畅&#xff0c;同时还会影响用户访问网站时的速度&#xff0c;所以&#xff0c;企业在搭建小程序时该如何选择合适的服务…...

【腾讯云架构师技术沙龙2025.03.22】

大模型技术演进与行业影响分析 日期&#xff1a;2025年3月22日 主讲人&#xff1a;李建忠 《DeepSeek实战驱动行业智变—AI应用寒武纪》 整理&#xff1a;飞书语音转化DeepSeek分析汇总 一、技术演进&#xff1a;从快思考到慢思考 1. 早期争议与能力局限&#xff08;2022-202…...

【jvm】垃圾回收的并行和并发

目录 1. 说明2. 并行&#xff08;Parallel&#xff09;2.1 定义2.2 特点2.3 示例 3. 并发&#xff08;Concurrent&#xff09;3.1 定义3.2 特点3.3 示例 4. 并行与并发的比较 1. 说明 1.在JVM&#xff08;Java虚拟机&#xff09;的垃圾回收机制中&#xff0c;并行&#xff08;…...

Flowable基础表结构

工作流程的相关操作都是操作存储在对应的表结构中&#xff0c;为了能更好的弄清楚Flowable的实现原理和细节&#xff0c;我们有必要先弄清楚Flowable的相关表结构及其作用。在Flowable中的表结构在初始化的时候会创建相关表结构&#xff0c;具体如下&#xff1a; ACT_EVT&…...

为什么不同的损失函数可以提升模型性能?

不同的损失函数可以提升模型性能的原因在于&#xff0c;损失函数是模型优化的核心目标&#xff0c;它直接定义了模型在训练过程中需要最小化的误差或偏差。通过设计不同的损失函数&#xff0c;可以针对具体任务的特点、数据分布的特性以及模型的目标需求进行更精确的优化&#…...

git上传文件到远程库

1.git init 把这个目录变成git可以管理的仓库 2.git status查看文件追踪的情况&#xff08;工作区的文件是红色&#xff09; 3.git add . 添加工作区所有文件到暂存区 再git status&#xff08;此时文件都变成绿色&#xff09; 4.git commit -m 描述性文字 5.git push -u o…...

【产品小白】需求分析的进阶

在产品经理的职业发展中&#xff0c;需求分析能力的提升至关重要。普通和进阶在需求分析层面&#xff0c;往往存在从表面需求到本质问题的认知差异。以下从几个方面探讨这一进阶过程&#xff1a; 1. 需求理解的深度 普通&#xff1a;​通常停留在用户表达的显性需求层面&#…...

机试题汇总

万能头文件 #include<bits/stdc.h> 输入一个年份和月份&#xff0c;输出该月的天数 1.3.5.7.8.10.12 -- 31天 闰年判断&#xff1a; year % 400 0 || (year % 4 0 && year % 100 ! 0&#xff09; 输入字符串&#xff0c;反转输出 #include<iostream&g…...

软件公司高新技术企业代办:机遇与陷阱并存-优雅草卓伊凡

软件公司高新技术企业代办&#xff1a;机遇与陷阱并存-优雅草卓伊凡 在科技飞速发展的当下&#xff0c;软件公司如雨后春笋般涌现&#xff0c;众多企业渴望通过申请高新技术企业来获得政策支持与发展助力。随之而来的&#xff0c;是高新技术企业代办业务的兴起。然而&#xff…...

C#中3维向量的实现

c#中默认不带库三维向量&#xff0c;需要自己安装第三方库&#xff0c;或者可以手动实现一个简易的三维向量。 public struct Vector3D {public double X { get; set; }public double Y { get; set; }public double Z { get; set; }public Vector3D(double x, double y, doubl…...

使用腾龙边缘计算网关内置的AIoTedge+NodeRED接入西门子PLC

腾龙边缘计算网关一体机凭借其强大的性能和丰富的功能&#xff0c;为企业提供了一种高效、灵活的解决方案。本文将详细介绍如何使用腾龙边缘计算网关一体机内置的AIoTedgeNodeRED接入西门子PLC&#xff0c;实现数据的采集、处理与传输。 一、硬件准备与环境搭建 在开始之前&am…...

基于MLA的人类语音情感分类

《DeepSeek大模型高性能核心技术与多模态融合开发&#xff08;人工智能技术丛书&#xff09;》(王晓华)【摘要 书评 试读】- 京东图书 随着信息技术的不断发展&#xff0c;如何让机器识别人类情绪&#xff0c;这个问题受到了学术界和工业界的广泛关注。目前&#xff0c;情绪识…...

Codeforces Round 1012 (Div. 2)

AB略 C 没看懂题意&#xff0c;翻译的问题。t0代表这个人必须找一个没有人的桌子且座位离他最近&#xff0c;t1代表这个人只要找一个空座位就可以了。一个桌子四个座位&#xff0c;t0肯定会坐左下角的那个。首先建立两个小根堆q1代表左下角的座位&#xff0c;q2代表一个桌子的…...

FPGA时钟约束

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、Create_clock 前言 时钟周期约束&#xff0c;就是对时钟进行约束。 一、Create_clock create_clock -name <name> -period <period> -waveform …...

二分查找------练习3

1. 题目 2. 思路和题解 这道题看到这个复杂度&#xff0c;就想到应该是使用二分查找进行求解。为了使二分查找的次数尽可能的少&#xff0c;我们需要对较短的数组进行查找&#xff0c;假设就在nums1上进行操作&#xff0c;因此在开始时&#xff0c;要对两个数组的长度进行一个…...