Linux基础-shell的简单实现
个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创Linux基础-shell的简单实现
收录于专栏[Linux学习]
本专栏旨在分享学习Linux的一点学习笔记,欢迎大家在评论区交流讨论💌
目录
1, 全局变量和常量定义
2. 环境信息获取
2.1 GetUserName
2.2 GetHostName
2.3 GetPwd
2.4 LastDir
3. 命令行提示符
3.1 MakeCommandLine
3.2 PrintCommandLine
4, 命令输入处理
4.1 GetCommandLine
4.2 ParseCommandLine
5. 命令调试
5.1 debug
6. 命令执行
6.1 ExecuteCommand
子进程执行命令:
等待子进程结束:
处理子进程的返回状态:
7. 环境变量管理
7.1 AddEnv
7.2 InitEnv
8. 内建命令处理
8.1 CheckAndExeBuiltCommand
8.1.1 cd命令
8.1.2 export命令
8.1.3 evn命令
8.1.4 echo命令
8.2 为什么使用内建命令
9. 主函数
10. 效果展示:
1, 全局变量和常量定义
功能 : 定义常量和全局变量,包括命令行参数、环境变量、当前工作目录、和最近的命令执行状态代码。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>using namespace std;const int basesize = 1024;
const int argvnum = 64;
const int envnum = 64;//全局的命令行参数
char *gragv[argvnum];
int gargc = 0;//全局变量
int lastcode = 0;//我的系统的环境变量
char *genv[envnum];//全局的当前shell工作路径
char pwd[basesize];
char pwdenv[basesize];
basesize: 定义了缓冲区的基础大小,用于存储用户输入的命令和路径。
argvnum: 定义最大命令行参数的数量。
envnum: 定义最大环境变量的数量。
gargv: 存储解析后的命令行参数的数组。
gargc: 表示当前解析出的参数数量。
lastcode: 保存最近执行命令的退出状态。
genv: 存储环境变量的数组。
pwd 和 pwdenv: 存储当前工作目录和环境变量PWD的缓冲区。
2. 环境信息获取
功能 : 获取当前用户、主机名和当前工作目录的信息,返回相应的字符串。
2.1 GetUserName
GetUserName: 获取当前用户的用户名,使用getenv从环境变量中获取,若未获取到,则返回"None"。
string GetUserName()
{string name = getenv("USER");return name.empty() ? "None" : name;
}
2.2 GetHostName
GetHostName: 获取主机名,类似于获取用户名的方式。
string GetHostName()
{string hostname = getenv("HOSTNAME");return hostname.empty() ? "None" : hostname;
}
2.3 GetPwd
GetPwd: 获取当前工作目录,使用getcwd函数获取并更新环境变量PWD。如果获取失败,返回"None"。
string GetPwd()
{if (nullptr == getcwd(pwd, sizeof(pwd)))return "None";snprintf(pwdenv, sizeof(pwdenv), "PWD=%s", pwd);putenv(pwdenv);return pwd;
}
补充知识:
snprintf 是一个安全的字符串格式化函数,用于将格式化的数据写入字符串。
pwdenv 是另一个字符数组,用于存储更新后的环境变量字符串。
这里,"PWD=%s" 是格式化字符串,%s 被当前工作目录的值(即 pwd 中的值)替换。最终结果类似于 PWD=/home/user(假设当前工作目录是 /home/user)。
putenv 是一个函数,用于设置环境变量。
通过调用 putenv(pwdenv),将之前构造的环境变量字符串 PWD=/path/to/current/dir 添加到进程的环境中。
注意,使用 putenv 要确保 pwdenv 的内容在后续使用中依然有效,因为 putenv 不会复制传入的字符串。
2.4 LastDir
LastDir: 从当前路径中提取最后一个目录名称,方便在命令行提示符中显示。
string LastDir()
{string curr = GetPwd();if (curr == "/" || curr == "None")return curr;size_t pos = curr.rfind("/");if (pos == std::string::npos)return curr;return curr.substr(pos + 1);
}
注意 : 这里curr == "/" || curr == "None" 我们都不需要额外处理, 直接返回就行, 因为curr为"/" 表示根目录, 为None时, 我们直接返会空就行
3. 命令行提示符
功能:生成和打印命令行提示符,包含用户、主机和当前目录信息。
3.1 MakeCommandLine
MakeCommandLine: 生成当前命令行提示符的字符串格式,包括用户、主机和当前目录。
string MakeCommandLine()
{//[XXX@XXXXX myshell]$ 这里就与普通命令行进行区分char command_line[basesize];snprintf(command_line, basesize, "[%s@%s %s]#", GetUserName().c_str(), GetHostName().c_str(), LastDir().c_str());return command_line;
}
3.2 PrintCommandLine
PrintCommandLine: 打印生成的命令行提示符到标准输出。
void PrintCommandLine()
{printf("%s", MakeCommandLine().c_str());fflush(stdout);
}
4, 命令输入处理
功能:从标准输入获取用户输入的命令,并解析成命令及其参数。
4.1 GetCommandLine
GetCommandLine: 从标准输入获取用户的命令行输入,使用fgets读取并处理换行符。
bool GetCommandLine(char command_buffer[], int size)
{//我们认为 : 我们要将用户出入的命令行 -> 当作一个完整的字符串//"ls -a -1 -n"char* result = fgets(command_buffer, size, stdin);if(!result){return false;}command_buffer[strlen(command_buffer) - 1] = 0;if(strlen(command_buffer) == 0) return false;return true;
}
补充知识:
fgets 是一个标准库函数,用于从标准输入(stdin)读取一行字符,最多读取 size - 1 个字符,并将其存储在 command_buffer 中。
fgets 会在读取到换行符 ('\n') 或 EOF(文件结束符)时停止读取,并会在 command_buffer 的末尾自动添加一个空字符 ('\0')。
如果成功读取,result 将指向 command_buffer;如果失败(例如,输入错误或 EOF),result 将为 nullptr。
注意: strlen(command_buffer) - 1 获取字符串的最后一个字符(换行符)的索引,并将其设为 0,以去掉换行符。
比如:我们输入 ls -a -l -n
fgets 会将缓冲区填充为: command_buffer = "ls -a -l -n\n\0"
经过strlen(command_buffer) - 1处理后 : "ls -a -l -n\0"
4.2 ParseCommandLine
ParseCommandLine: 使用strtok将输入的命令行字符串分割为单独的命令和参数,并存储在gargv数组中。
void ParseCommandLine(char command_buffer[], int len)
{(void)len;memset(gargv, 0, sizeof(gargv));gargc = 0;//"ls -a -l -n"const char *sep = " ";gargv[gargc++] = strtok(command_buffer, sep);//=是刻意写的while((bool)(gargv[gargc++] = strtok(nullptr, sep)));gargc--;
}
补充知识:
strtok 函数会将 command_buffer 字符串中的第一个分隔符(空格)替换为 \0,并返回指向第一个标记的指针,存储到 gargv 数组中。
strtok(nullptr, sep) 意味着继续解析之前传入的字符串。
注意 (bool) 转换是为了确保表达式的结果为布尔值,这样可以明确表示循环的条件。
5. 命令调试
5.1 debug
功能 : 输出当前命令参数的数量和每个参数的值,以帮助开发和调试。
void debug()
{printf("argc: %d\n", gargc);for(int i = 0; gargv[i]; i++){printf("argv[%d]: %s\n", i, gargv[i]);}
}
6. 命令执行
6.1 ExecuteCommand
功能:通过fork()和execvpe()创建子进程执行用户命令,并等待其完成。
bool ExecuteCommand()
{//让子进程进行执行pid_t id = fork();if(id < 0) return false;if(id == 0){//子进程//1. 执行命令execvpe(gargv[0], gargv, genv);//2. 退出exit(1);}int status = 0;pid_t rid = waitpid(id, &status, 0);if(rid > 0){if(WIFEXITED(status)){lastcode = WEXITSTATUS(status);}else{lastcode = 100;}return true;}return false;
}
子进程执行命令:
execvpe(gargv[0], gargv, genv);:execvpe 用于执行指定的命令。它会用新的程序替换当前进程(子进程)。参数说明:
gargv[0]:命令的名称(通常是命令的路径)。
gargv:一个字符串数组,包含传递给命令的参数。
genv:一个字符串数组,包含环境变量。
如果 execvpe 成功,当前进程(子进程)将被新的程序替换,之后的代码将不会执行。
如果 execvpe 失败(例如命令未找到),子进程将执行 exit(1),返回状态 1,以指示错误。
等待子进程结束:
int status = 0;:用于存储子进程的退出状态。
waitpid(id, &status, 0):在父进程中调用,等待指定的子进程(由 id 指定)结束。结果存储在 status 变量中。
返回值 rid:如果成功,返回已结束子进程的 PID;如果失败,返回 -1。
处理子进程的返回状态:
if(rid > 0):确认 waitpid 调用成功,rid 应该是大于 0 的子进程 PID。
WIFEXITED(status):这个宏检查子进程是否正常退出(通过 exit() 或 return 语句)。
WEXITSTATUS(status):如果子进程正常退出,获取其返回状态并将其存储在 lastcode 中。
如果子进程未正常退出(例如由于信号导致的终止),则将 lastcode 设置为 100,这通常用于指示异常情况。
return true;:表示成功执行命令并处理了其退出状态。
7. 环境变量管理
功能:动态分配内存,将新的环境变量添加到genv数组中。
7.1 AddEnv
void AddEnv(const char* item)
{int index = 0;while(genv[index]){index++;}genv[index] = (char*)malloc(strlen(item) + 1);strncpy(genv[index], item, strlen(item) + 1);genv[++index] = nullptr;
}
功能 : 添加环境变量:该函数接受一个字符串 item 作为参数,并将其添加到 genv 环境变量数组中。
逐行分析
int index = 0;:初始化索引为 0,用于遍历 genv 数组。
while(genv[index]):遍历 genv 数组,直到找到第一个空指针,表示可以插入新环境变量的位置。
genv[index] = (char*)malloc(strlen(item) + 1);:
为新的环境变量分配内存。malloc 分配的内存大小为 item 字符串的长度加 1(为字符串结束符 \0 留出空间)。
strncpy(genv[index], item, strlen(item) + 1);:
将 item 的内容复制到 genv[index] 中。使用 strncpy 复制到长度 strlen(item) + 1,确保包含字符串结束符。
genv[++index] = nullptr;:
在数组中下一个位置设置为 nullptr,标志着环境变量的结束。
7.2 InitEnv
void InitEnv()
{extern char **environ;int index = 0;while(environ[index]){genv[index] = (char*)malloc(strlen(environ[index] + 1));strncpy(genv[index], environ[index], strlen(environ[index] + 1));index++;}genv[index] = nullptr;
}
功能 : 初始化环境变量:该函数从系统环境变量中读取所有环境变量并将其存储在 genv 数组中。
逐行分析
extern char **environ;:声明外部变量 environ,这是一个指向环境变量字符串数组的指针
int index = 0;:初始化索引为 0,用于遍历 environ。
while(environ[index]):遍历 environ 数组,直到找到第一个空指针,表示所有环境变量都已读取。
genv[index] = (char*)malloc(strlen(environ[index]) + 1);:
为每个环境变量分配内存。这里 strlen(environ[index]) 计算字符串的长度,并加 1 来包含 \0 结束符。
strncpy(genv[index], environ[index], strlen(environ[index] + 1));:
将 environ[index] 的内容复制到 genv[index] 中。这里同样存在一个错误,应该是 strncpy(genv[index], environ[index], strlen(environ[index]) + 1);。
index++;:增加索引,以便处理下一个环境变量。
genv[index] = nullptr;:在数组最后设置 nullptr,表示环境变量的结束
8. 内建命令处理
8.1 CheckAndExeBuiltCommand
bool CheckAndExeBuiltCommand()
{if(strcmp(gargv[0], "cd") == 0){//内建命令if(gargc == 2){chdir(gargv[1]);lastcode = 0;}else{lastcode = 1;}return true;}else if(strcmp(gargv[0], "export") == 0){//export也是内建命令if(gargc == 2){AddEnv(gargv[1]);lastcode = 0;}else{lastcode = 2;}return true;}else if(strcmp(gargv[0], "env") == 0){for(int i = 0; genv[i]; i++){printf("%d\n", genv[i]);}lastcode = 0;return true;}else if(strcmp(gargv[0], "echo") == 0){if(gargc == 2){//echo $?//echo $PATH//echo helloif(gargv[1][0] == '$'){if(gargv[1][1] == '?'){printf("%d\n", lastcode);lastcode = 0;}else{printf("%s\n", gargv[1]);lastcode = 0;}}else{lastcode = 3;}return true;}return false;}
}
8.1.1 cd命令
功能:用于更改当前工作目录。
逻辑:
检查参数个数 gargc 是否等于 2(即命令和目录)。
如果参数正确,调用 chdir 函数改变目录,并将 lastcode 设置为 0,表示成功。
如果参数不正确,将 lastcode 设置为 1,表示错误。
chdir() : 将调用进程的当前工作目录更改为path中指定的目录
8.1.2 export命令
功能:用于设置或导出环境变量。
逻辑:
同样检查参数个数 gargc 是否为 2。
如果正确,调用 AddEnv 函数添加环境变量,并将 lastcode 设置为 0。
如果参数不正确,设置 lastcode 为 2。
8.1.3 evn命令
功能:列出所有环境变量。
逻辑:
遍历 genv 数组,打印每个环境变量。
将 lastcode 设置为 0。
8.1.4 echo命令
功能:输出字符串或变量。
逻辑:
检查参数个数是否为 2。
如果是,检查 gargv[1] 的第一个字符是否为 $:
如果是 $?,输出 lastcode 的值。
如果是其他以 $ 开头的字符串,直接输出这个字符串(假设它是环境变量)。
如果没有 $,则将 lastcode 设置为 3。
如果参数个数不正确,返回 false。
8.2 为什么使用内建命令
快速响应:内建命令通常直接在 shell 进程内执行,无需创建新的进程,减少了上下文切换的开销。这使得内建命令的执行速度更快。
基本功能:内建命令提供了一些与 shell 紧密相关的基本功能,如改变目录(cd)、设置环境变量(export)、获取当前环境(env)等,这些操作通常与 shell 的状态直接相关。
环境影响:某些内建命令(如 cd)会影响 shell 的状态(例如当前工作目录),如果用外部程序实现,改变的状态不会反映到 shell 中。
简化用户操作:用户可以直接使用内建命令而无需担心路径问题。例如,cd 命令只需要提供目标路径,而不必寻找相应的外部可执行文件。
状态保持:内建命令如 echo 和 export 能够直接访问 shell 的状态和环境变量,而不需要通过外部程序来管理,这样可以更好地处理如 $?(上一个命令的退出状态)这样的特殊情况。
9. 主函数
功能:主程序循环,负责显示提示符、获取用户命令、解析命令、检查内建命令,并执行命令。
int main()
{InitEnv();char command_buffer[basesize];while(true){//1. 命令行提示符PrintCommandLine();//command_buffer -> output//2. 获取用户命令if(!GetCommandLine(command_buffer, basesize)){continue;}//3. 解析命令ParseCommandLine(command_buffer, strlen(command_buffer));if(CheckAndExeBuiltCommand()){continue;}4. 执行命令ExecuteCommand();}return 0;
}
10. 效果展示:
相关文章:

Linux基础-shell的简单实现
个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 Linux基础-shell的简单实现 收录于专栏[Linux学习] 本专栏旨在分享学习Linux的一点学习笔记,欢迎大家在评论区交流讨论💌 目录 1, 全局变…...

Tomcat日志文件详解及catalina.out日志清理方法
目录 前言1. Tomcat日志文件详解1.1 catalina.out1.2 localhost_access_log1.3 catalina.<date>.log1.4 host-manager.<date>.log 和 manager.<date>.log1.5 localhost.<date>.log 2. catalina.out文件管理与清理方法2.1 为什么不能直接删除catalina.o…...

react 中的hooks中的useState
(1). State Hook让函数组件也可以有state状态, 并进行状态数据的读写操作 (2). 语法: const [xxx, setXxx] React.useState(initValue) (3). useState()说明:参数: 第一次初始化指定的值在内部作缓存返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的…...

STM32学习笔记---DMA
目录 一、什么是DMA 1、DMA是什么 2、DMA的工作流程 3、DMA控制器与外设控制器 二、如何配置DMA 1、DMA框图 2、功能说明 2.1 通道选择 2.2 仲裁器 2.3 源、目标和传输模式 2.4 指针递增 2.5 循环模式 2.6 DMA流控制器和外设流控制器 3、程序设计 三、具体使用DMA…...

Cesium 实战 - 自定义纹理材质 - 立体墙(旋转材质)
Cesium 实战 - 自定义纹理材质 - 立体墙(旋转材质) 核心代码完整代码在线示例Cesium 给实体对象(Entity)提供了很多实用的样式,基本满足普通项目需求; 但是作为 WebGL 引擎,肯定不够丰富,尤其是动态效果样式。 对于实体对象(Entity),可以通过自定义材质,实现各种…...

进程间关系与守护进程
一、进程组 1.1、什么是进程组 提到进程的概念, 其实每一个进程除了有一个进程 ID(PID)之外 还属于一 个进程组。进程组是一个或者多个进程的集合, 一个进程组可以包含多个进程。 每一 个进程组也有一个唯一的进程组 ID(PGID), 并且这个 PG…...

金山翻译接口逆向
网址(加密后):aHR0cHM6Ly93d3cuaWNpYmEuY29tL3RyYW5zbGF0ZQ 文章目录 抓包sign值结果加密 逆向sign值第一步第二步1.2.3. 解密content第一步1.2.3. 抓包 F12 -> 翻译框输入spider -> 点击Fetch/XHR -> 找到接口 index.php? 开头的…...
unified-runtime编译与验证
unified-runtime编译与验证 一.创建容器二.编译unified-runtime三.生成一个cuda ptx kernel四.API测试 unified-runtime编译与验证 一.创建容器 docker run --gpus all --shm-size32g -ti \-e NVIDIA_VISIBLE_DEVICESall --privileged --nethost \--rm -it \-v $PWD:/home \-…...
【Python】最详细--基础语法
Python是一种强大且易于学习的编程语言,广泛用于各种应用程序的开发,如web开发、数据科学、人工智能等。以下是一些Python的基础知识: 1. Python的注释 Python的注释用于在代码中添加说明,以提高代码的可读性。注释在代码执行时…...
二叉树基础:什么样的二叉树适合用数组来存储?
二叉树基础:什么样的二叉树适合用数组来存储? 在计算机科学中,二叉树是一种非常重要的数据结构。它具有许多应用,如搜索、排序、表达式解析等。在存储二叉树时,我们可以使用多种方法,其中一种是使用数组。但是,并不是所有的二叉树都适合用数组来存储。那么,什么样的二…...

iTOP-RK3568开发板独立NPU通过算法加特应用到以下的场景
iTOP-3568开发板采用瑞芯微RK3568处理器,内部集成了四核64位Cortex-A55处理器。主频高达2.0Ghz,RK809动态调频。集成了双核心架构GPU,ARM G52 2EE、支持OpenGLES1.1/2.0/3.2、OpenCL2.0、Vulkan1.1、内嵌高性能2D加速硬件。 内置独立NPU,算力…...

Java基于SpringBoot微信小程序的跳蚤市场系统设计与实现(lw+数据库+讲解等)
项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念,提供了一套默认的配置,让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…...
【分布式微服务云原生】《Redis 的高效之道:线程模型、IO 模型与 Reactor 模型全解析》
标题:《分布式缓存Redis 的高效之道:线程模型、IO 模型与 Reactor 模型全解析》 摘要:本文深入探讨分布式缓存 Redis 的 I线程模型、IO 模型以及 Reactor 模型。详细介绍了 Redis 在不同版本中的线程变化、IO 模型的特点和工作流程ÿ…...

科研类型PPT的制作技巧
目录 科研类型PPT的制作技巧 荣誉: 首页:ppt开头结尾 小标题 重点标记:加粗红色下划线 使用三线表 图片,文本排版 一、明确目的与受众分析 二、基础设计原则 三、内容组织与呈现 四、绘图与模型制作 五、其他注意事项 科研类型PPT的制作技巧 荣誉: 首页:ppt开…...

rom定制系列------小米6x_MIUI14_安卓13刷机包修改写入以及功能定制 界面预览
在接待一些定制化系统中。有很多工作室或者一些特殊行业的友友需要在已有固件基础上简略修改其中的功能。方便使用。例如usb调试默认开启。usb安装设置以及usb安装与内置删减一些app的定制服务。今天给友友预览其中小米6X此款机型定制相关的一些界面与功能演示。 定制机型以及…...

线性代数基础02
目录 1.向量 1.1向量的定义 1.2向量的运算 1.2.1向量加法 1.2.2向量数乘 1.2.3向量点积 1.3矩阵的特征值和特征向量 1.4向量的模 1.4.1向量的模的定义 1.4.2向量的模的几何解释 1.4.3向量的模的性质 1.5向量的内积 1.5.1向量的内积的定义 1.5.2向量的内积的几何解…...
「4.4」祖孙询问
「4.4」祖孙询问 题目描述 已知一棵 n 个节点的有根树。有 m 个询问,每个询问给出了一对节点的编号 x 和 y,询问 x 与 y 的祖孙关系。 输入格式 输入第一行包括一个整数 n 表示节点个数; 接下来 n 行每行一对整数对 a 和 b 表示 a 和 b 之…...

Datawhale 组队学习 文生图 Prompt攻防 task03随笔
这期我们从不同角度切入探讨赛题的进阶思路 思路1:对比不同大模型 首先我们可以选择尝试不同的大模型,使用更复杂的大模型可以提高文本改写的质量和效果。随着模型大小的增加,其表示能力也随之增强,能够捕捉更细微的语言特征和语…...

游戏投屏软件有哪些?分享这10款比较好用的!
说到投屏,这个事情我还是比较有发言权的! 一般手机下载个APP,然后就可以通过WiFi、蓝牙或者USB进行连接投屏啦,下面是国内比较主流的一些游戏投屏软件,可以根据他们的优缺点进行选择哦! 01.幕连 国内首款…...

[Unity Demo]从零开始制作空洞骑士Hollow Knight第十六集(下篇):制作小BOSS龙牙哥
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、制作小BOSS龙牙哥 1.导入素材制作动画2.制作两种攻击行为3.制作从惊醒到转身到走路or跑步行为总结 前言 hello大家好久没见,之所以隔了一天时间…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...

自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...
Linux安全加固:从攻防视角构建系统免疫
Linux安全加固:从攻防视角构建系统免疫 构建坚不可摧的数字堡垒 引言:攻防对抗的新纪元 在日益复杂的网络威胁环境中,Linux系统安全已从被动防御转向主动免疫。2023年全球网络安全报告显示,高级持续性威胁(APT)攻击同比增长65%,平均入侵停留时间缩短至48小时。本章将从…...

何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡
何谓AI编程【02】AI编程官网以优雅草星云智控为例建设实践-完善顶部-建立各项子页-调整排版-优雅草卓伊凡 背景 我们以建设星云智控官网来做AI编程实践,很多人以为AI已经强大到不需要程序员了,其实不是,AI更加需要程序员,普通人…...

Qwen系列之Qwen3解读:最强开源模型的细节拆解
文章目录 1.1分钟快览2.模型架构2.1.Dense模型2.2.MoE模型 3.预训练阶段3.1.数据3.2.训练3.3.评估 4.后训练阶段S1: 长链思维冷启动S2: 推理强化学习S3: 思考模式融合S4: 通用强化学习 5.全家桶中的小模型训练评估评估数据集评估细节评估效果弱智评估和民间Arena 分析展望 如果…...