制作人是干嘛的/成都seo学徒
控制欲强?视奸?普通人那才叫视奸,您是皇帝,天下大事无一逃过您的耳目,您想看什么就看什么,臣怀疑他在朋友圈私养兵士,囤积枪甲,蓄意谋反,图谋皇位啊!
哈哈哈哈开个玩笑,这篇就主要讲讲Linux进程的控制吧~
fork( )
由于fork()之前也说过啦(从已存在进程中创建一个新进程:新进程为子进程,原进程为父进程),所以下面主要讲内核的操作,进程调用fork,当控制转移到内核中的fork代码后,内核做:
1.分配新的内存块和内核数据结构给子进程
2.将父进程部分数据结构内容拷贝至子进程
3.添加子进程到系统进程列表当中
4.fork返回,开始调度器调度
当一个进程调用fork之后,就有两个二进制代码相同的进程。而且它们都运行到相同的地方。但每个进程都将可以 开始它们自己的旅程:
#include <unistd.h>
#include<stdio.h>
int main(void)
{pid_t pid;printf("Before: pid is %d\n", getpid());if ((pid = fork()) == -1)perror("fork()"), exit(1);printf("After:pid is %d, fork return %d\n", getpid(), pid);sleep(1);return 0;
}
先来下个定义:
进程=内核的相关管理数据结构(task_struct + mm_struct + 页表)+ 代码和数据
已知fork函数的返回值是这样的:
子进程返回0
父进程返回子进程的pid
那为什么捏?
原因其实也很简单,爹得知道儿子名,杀掉他啊等待他啊,爹总要知道的(为了方便父进程对紫禁城进行标识,进而进行管理)
进程具有独立性就在于紫禁城代码数据和父进程共享,但因为写时拷贝又不影响父进程
fork常规用法
一个父进程希望复制自己,使父子进程同时执行不同的代码段(父进程等待客户端请求,生成子 进程来处理请求)
一个进程要执行一个不同的程序(子进程从fork返回后,调用exec函数)
fork调用失败原因
系统中有太多的进程
实际用户的进程数超过了限制
进程终止
终止是在做什么
进程终止就是在释放曾经的代码和数据所占据的空间,也是在释放内核数据结构(task_struct,当进程状态是Z就要释放对应PCB)
终止三种情况
先来看两段代码:
#include<stdio.h>
#include<unistd.h>int main()
{printf("hello world!\n");return 0;
}
#include<stdio.h>
#include<unistd.h>int main()
{printf("hello world!\n");return 100;
}
只有返回值不一样对吧,对?取内容会发现也不一样:
echo是内建命令,打印的都是bash内部的变量数据
?:父进程bash获取到的最近一个紫禁城的退出码 (0:成功,!0:失败)
退出码存在意义:告诉关心方(父进程)任务完成如何
因为成功的退出码就是0,而!0有很多,所以不同!0值一方面表示失败,一方面还表示失败的原因
可以这样打印下错误信息:
#include<stdio.h>
#include<unistd.h>
#include<string.h>int main()
{int errcode = 0;for (errcode = 0; errcode <= 255; errcode++){printf("%d:%s\n", errcode, strerror(errcode));}return 0;
}
那么父进程知道紫禁城退出码因为点撒捏?
因为:!要知道紫禁城退出情况,正常退出了嘛,错误了嘛,错哪了呀,,,
错误码可以自己设定:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
int Div(int x, int y)
{if (0 == y){return -1;}else{return x / y;}
}
int main()
{printf("%d\n",Div(-1,1));return 0;
}
但是这样没法判断是y==0导致返回错误码-1,还是本来的计算结果就是-1
所以可以这样改:
#include<stdio.h>
#include<unistd.h>
#include<string.h>//自定义枚举常量
enum
{Success = 0,Div_Zero,Mod_Zero,
};int exit_code = Success;int Div(int x, int y)
{if (0 == y){exit_code = Div_Zero;return -1;}else{return x / y;}
}
int main()
{printf("%d\n", Div(-1, 1));return exit_code;
}
还可以接着写接口补充错误信息:
#include<stdio.h>
#include<unistd.h>
#include<string.h>//自定义枚举常量
enum
{Success = 0,Div_Zero,Mod_Zero,
};int exit_code = Success;const char* CodeToErrString(int code)
{switch (code){case Success:return "Success";case Div_Zero:return "div zero!";case Mod_Zero:return "mod zero!";default:return "unknow error!";}
}int Div(int x, int y)
{if (0 == y){exit_code = Div_Zero;return -1;}else{return x / y;}
}
int main()
{printf("%d\n", Div(-1, 1));printf("%s\n", CodeToErrString(exit_code));return exit_code;
}
来看看进程终止的三种情况吧:
1.代码跑完,结果正确
2.代码跑完,结果不正确(正确与否可通过进程退出码决定)
3.代码执行时,出现了异常,提前退出了(系统&&自定义退出码)
什么是崩溃?
就是编译运行的时候,操作系统发现你的进程做了不该做的是事,于是OS杀掉了你的进程
那异常了退出码还有意义吗(肯定没有啊,作弊拿到60和作弊拿到100被抓没区别)
进程出现了异常,本质是因为进程收到了OS发给进程的信号
比如说,来上一份妇孺皆知的代码:
#include<stdio.h>
#include<unistd.h>
int main()
{while (1){printf("I am a process,pid:%d\n", getpid());}return 0;
}
这进程能一直运行下去,但是我们可以通过kill的方式干掉它:
kill -9 pid;
这进程没有出现异常,但是由于进程收到了OS发给进程的信号,所以进程不得不终止
再来一瓶野指针:
#include<stdio.h>
#include<unistd.h>
int main()
{int* p = NULL;while (1){printf("I am a process,pid:%d\n", getpid());sleep(1);*p = 100; //看好了小登中登老登,这是故意哒!}return 0;
}
在Linux中运行这段代码会发现出现段错误:Segmentation fault:
不嘻嘻 ,段错误,OS提前终止进程
我们通过观察进程退出的时候退出信号是多少就可以判断我们的进程为何异常了
判断流程:
1.先确认是否异常
2.不是异常就是代码跑完了,直接看退出码
衡量一个进程退出,只需要两个数字:退出码,退出信号
进程退出时会把退出码和退出信号写入PCB(方便父进程知道)
如何进行终止
main函数return就表示进程终止啦(非main函数return,代表函数结束)
代码调用exit函数(头文件为stdlib.h)
exit(0); //里面数字是return数
还有个东西叫_exit( )
和exit的区别就是,它在程序结束的时候并不会冲刷缓冲区
缓冲区必定在_exit()之上
exit在调用_exit前还做了其他工作:
1. 执行用户通过 atexit或on_exit定义的清理函数
2. 关闭所有打开的流,所有的缓存数据均被写入
3. 调用_exit
除了exit,return是一种更常见的退出进程方法。执行return n等同于执行exit(n)(调用main的运行时函数会将main的返回值当做 exit的参数)
进程等待
是什么
任何子进程在退出的情况下,一般必须要被父进程进行等待
为什么捏?
你想奥,如果进程在退出时,父进程不管不顾,退出进程,状态将会变成Z(僵尸状态),发生内存泄漏(进程一旦变成僵尸状态,那就刀枪不入,“杀人不眨眼”的kill -9 也无能为力,因为谁也没有办法杀死一个已经死去的进程,就像是永远没办法叫醒一个装睡的人)
1.父进程通过等待,解决紫禁城退出的僵尸问题,回收系统资源(一定要考虑的)
2.获取紫禁城的退出信息知道紫禁城是什么原因退出的(可选功能)
怎么办
要来看两个可爱的函数:wait、waitpid
wait:
返回值:等待成功时,紫禁城pid
参数:等待任意一个紫禁城退出(是输出型的参数,获取紫禁城退出状态,不关心可以置NULL)
pid_t wait(int* status);
上代码!
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>void ChildRun()
{int cnt = 5;while (cnt){printf("I am child process,pid:%d,ppid:%d\n", getpid(), getppid());sleep(1);cnt--;}
}int main()
{printf("I am father,pid:%d,ppid:%d\n", getpid(), getppid());pid_t id = fork();if (id == 0){ChildRun();printf("child quit ...\n");exit(0);}sleep(3);pid_t rid = wait(NULL);if (rid > 0){printf("wait success,rid:%d\n", rid);}sleep(3);printf("father quit\n");return 0;
}
一遍运行一边开监控脚本看看怎么个事:
while :; do ps ajx | head -1 && ps ajx | grep myprocess | grep -v grep; sleep 1;done
可以看到紫禁城在被父进程回收前是处于僵尸状态的:
父进程在等待时候也没干其他事,只是等
给大家看看单核处理器小猫:
polo tiu ~,橘域网链接已断开
如果紫禁城没有退出,父进程其实一直在进行阻塞等待
紫禁城本身就是软件,父进程本质是在等待某种软件条件就绪
阻塞等待?
怎么个事?
等待硬件or软件,本质都是数据结构对象
来康康waitpid:
关于这个就改一下就好:
pid_t rid = waitpid(-1, NULL, 0);
作用和上面的也一样(-1是在等任意一个的意思),等待紫禁城,等待到了哪个就返回哪个,那样的还准备俩函数干啥,别着急,这样就能等待特定的了,我是在等,可我在等的只是你:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>void ChildRun()
{int cnt = 5;while (cnt){printf("I am child process,pid:%d,ppid:%d\n", getpid(), getppid());sleep(1);cnt--;}
}int main()
{printf("I am father,pid:%d,ppid:%d\n", getpid(), getppid());pid_t id = fork();if (id == 0){ChildRun();printf("child quit ...\n");exit(0);}sleep(3);pid_t rid = waitpid(id, NULL, 0);if (rid > 0){printf("wait success,rid:%d\n", rid);}sleep(3);printf("father quit\n");return 0;
}
也是可能失败的(但基本上不会失败):
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>void ChildRun()
{int cnt = 5;while (cnt){printf("I am child process,pid:%d,ppid:%d\n", getpid(), getppid());sleep(1);cnt--;}
}int main()
{printf("I am father,pid:%d,ppid:%d\n", getpid(), getppid());pid_t id = fork();if (id == 0){ChildRun();printf("child quit ...\n");exit(0);}sleep(3);pid_t rid = waitpid(id+1, NULL, 0);if (rid > 0){printf("wait success,rid:%d\n", rid);}else{printf("wait failed\n");}sleep(3);printf("father quit\n");return 0;
}
再来回看这个函数:
pid_t waitpid(pid_t pid, int status, int options);
返回值:
当正常返回的时候waitpid返回收集到的子进程的进程ID(等待成功,紫禁城退出
父进程回收成功)
若返回值为0,那证明检测成功,但紫禁城并未退出,需要再次进行等待
若设置了选项WNOHANG,调用中waitpid发现没有已退出的子进程可收集,则返回0
如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在
参数:
Pid:
Pid=-1:等待任一个子进程,与wait等效
Pid>0:等待其进程ID与pid相等的子进程
Status:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码(查看进程的退出码)
options:
WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待
若正常结束,则返回该子进程的ID
若子进程已经退出,调用wait/waitpid时,
wait/waitpid会立即返回,并且释放资源,获得子进程退出信息
若在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞
若不存在该子进程,则立即出错返回
退出信息就退出码和退出信号啦,可是Status只有一个数哎(别猜了人家有特殊格式,可以当做位图看待,图中表示比特位):
退出码:0~255(最多就那么多)
这样可以直接看:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>void ChildRun()
{int cnt = 5;while (cnt){printf("I am child process,pid:%d,ppid:%d\n", getpid(), getppid());sleep(1);cnt--;}
}int main()
{printf("I am father,pid:%d,ppid:%d\n", getpid(), getppid());pid_t id = fork();if (id == 0){ChildRun();printf("child quit ...\n");exit(49);}sleep(3);int status = 0;pid_t rid = waitpid(id, &status , 0);if (rid > 0){printf("wait success,rid:%d\n", rid);}else{printf("wait failed\n");}sleep(3);printf("father quit,status:%d,child quit code:%d,child quit signal:%d\n",status,(status>>8)&0xFF, status & 0x7F);return 0;
}
退出后会发现是正常退出的:
上面的宏和这个位操作差不多,使用的话就是(结果是紫禁城退出码,想知道退出信号就自己去按位与去):
if(WIFEXITED(status))
很好,正和我意
那假如紫禁城死循环怎么办?
看看不就知道了:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>void ChildRun()
{int cnt = 5;while (1){printf("I am child process,pid:%d,ppid:%d\n", getpid(), getppid());sleep(1);cnt--;}
}int main()
{printf("I am father,pid:%d,ppid:%d\n", getpid(), getppid());pid_t id = fork();if (id == 0){ChildRun();printf("child quit ...\n");exit(123);}sleep(3);int status = 0;pid_t rid = waitpid(id, &status , 0);if (rid > 0){printf("wait success,rid:%d\n", rid);}else{printf("wait failed\n");}sleep(3);printf("father quit,status:%d,child quit code:%d,child qiut signal:%d\n",status,(status>>8)&0xFF, status & 0x7F);return 0;
}
当然是爹一直等了,,,把紫禁城干掉回收
如果紫禁城异常怎么办?
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>void ChildRun()
{int cnt = 5;int* p = NULL;while (cnt){printf("I am child process,pid:%d,ppid:%d\n", getpid(), getppid());sleep(1);cnt--;}*p = 10;
}int main()
{printf("I am father,pid:%d,ppid:%d\n", getpid(), getppid());pid_t id = fork();if (id == 0){ChildRun();printf("child quit ...\n");exit(123);}sleep(3);int status = 0;pid_t rid = waitpid(id, &status , 0);if (rid > 0){printf("wait success,rid:%d\n", rid);}else{printf("wait failed\n");}sleep(3);printf("father quit,status:%d,child quit code:%d,child qiut signal:%d\n",status,(status>>8)&0xFF, status & 0x7F);return 0;
}
也看看:
可以发现直接挂了,退出信息告诉程序猿:赶紧回去查查你的代码,有bug!!!
如果紫禁城没有退出,父进程在进行执行waitpid进行等待(等待某种条件发生,只不过如今的条件恰好是紫禁城退出),阻塞等待(进程阻塞,父进程什么事都没干)
但是现在我们使用的大部分进程都是阻塞板的,WNOHANG选项就是非阻塞等待,如果一直hang住什么都做不了,我们把这种情况叫做服务器宕机
讲个小故事来阐述这个故事吧:
从前有一只学生名为燃燃子,她舍友是个学霸叫挽鸢(超级厉害,什么都会的那种,你问她要课堂笔记没有一个是不记录的,平时都不逃课),有天燃燃子给挽鸢说,宝宝下午C语言要考试了,给我画个重点呗,考完咱俩出去吃好吃的我请客,挽鸢欣然答应,但是挽鸢当时正在学cpp的一本书,就问燃燃子能不能等她半小时,她学完就干,燃燃子一听说那好吧,你先忙,燃燃子在等待挽鸢的过程中,一会开局王者,一会刷会视频号,一会拿出书装样子看看,过了差不多半小时,燃燃子给挽鸢打电话,问她好了没,挽鸢说还有两分钟就好(怎么可能),等待是周而复始的,但燃燃子在等待挽鸢的过程中还做了其他事,所以这是非阻塞等待,打电话的过程是函数调用(调用的本质是在检测挽鸢的状态),燃燃子和挽鸢说话的过程是函数传参,挽鸢告诉燃燃子自己还需要一会的过程就是函数返回值
故事拉长,燃燃子在挽鸢的帮助下顺利考过了C语言考试,燃燃子狂喜,但是先别急着高兴,过两天考操作系统了(燃燃子:我嘞个骚刚,操作系统是啥啊),于是燃燃子顺理成章找到挽鸢,哎嘿能不能再帮我划个操作系统重点,这两天饭我包了,挽鸢说OK啊,但是挽鸢当时在学Linux网络编程,就问燃燃子能不能等她一会,她还没看完,但是燃燃子觉得来回打电话有点麻烦,就和挽鸢说你不用挂电话,就把手机放旁边,好了直接叫我就好,这个时候燃燃子墨墨听着电话那头的无尽的翻书声,只是沉默着,她什么也没干,这个时候燃燃子在进行的是阻塞等待(同时状态不就绪就不返回),这时路过一只笙宝,看燃燃子啥也不干就在那扒着手机听听听,于是笙宝过去问:“干啥呢干在这坐着”,燃燃子也不理,过会笙宝自讨没趣走了,那燃燃子为何要进行这样的苦等呢?有很多种可能,可能单纯就是想等着,还有可能是挽鸢比较受欢迎,不太容易约到(但是阻塞等待在现实中不太能存在吧,应该),waitpid检测紫禁城状态变化的
当我们采用非阻塞等待的时候,一般要加上循环,直到检测到紫禁城退出,我们把这种方案叫做非阻塞轮询方案
而阻塞等待优点也很明显了,就是简单可靠,但非阻塞时父进程可以做其他的事
各有千秋
写段非阻塞轮询的代码吧:
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<unistd.h>void ChildRun()
{int cnt = 5;while (cnt){printf("I am child process,pid:%d,ppid:%d,cnt:%d\n", getpid(), getppid(), cnt);cnt--;sleep(1);}
}int main()
{printf("I am father process,pid:%d,pid:%d\n", getpid(), getppid());pid_t id = fork();if (id == 0){ChildRun();printf("child quit\n");exit(123);}while (1){int status = 0;pid_t rid = waitpid(id, &status, WNOHANG); //进行非阻塞等待if (rid == 0){printf("child is running, father check next time!\n");//DoOtherThing();}else if (rid > 0){if (WIFEXITED(status)){printf("child quit success,child exit code:%d\n", WEXITSTATUS(status));}else{printf("child quit unnormal!\n");}break;}else{printf("waitpid failed!\n");break;}}return 0;
}
刚说在父进程等待的时候还可以做其他事,下面来举个栗子:基于函数指针级别的对父进程完成任务进行解耦
myprocess.c
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<unistd.h>
#include"task.h"typedef void(*func_t)();#define N 3
func_t tasks[N] = { NULL };void LoadTask()
{tasks[0] = Printlog;tasks[1] = Download;tasks[2] = MysqlDataSync;
}void HanderTask()
{for (int i = 0; i < N; i++){tasks[i]();}
}void DoOtherThing()
{HanderTask();
}void ChildRun()
{int cnt = 5;while (cnt){printf("I am child process,pid:%d,ppid:%d,cnt:%d\n", getpid(), getppid(), cnt);cnt--;sleep(1);}
}int main()
{printf("I am father process,pid:%d,pid:%d\n", getpid(), getppid());pid_t id = fork();if (id == 0){ChildRun();printf("child quit\n");exit(123);}LoadTask();while (1){int status = 0;pid_t rid = waitpid(id, &status, WNOHANG); //进行非阻塞等待if (rid == 0){printf("child is running, father check next time!\n");//DoOtherThing();}else if (rid > 0){if (WIFEXITED(status)){printf("child quit success,child exit code:%d\n", WEXITSTATUS(status));}else{printf("child quit unnormal!\n");}break;}else{printf("waitpid failed!\n");break;}}return 0;
}
task.h
#pragma once
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<unistd.h>void Printlog();
void Download();
void MysqlDataSync();
task.c
#include"task.h"void Printlog()
{printf("begin Printlog...\n");
}void Download()
{printf("begin Download...\n");
}void MysqlDataSync()
{printf("begin MysqlDataSync...\n");
}
makefile
myprocess:myprocess.c task.c
gcc - o $@ $ ^
.PHONT:clean
clean:rm -f myprocess
父进程就完成了在轮询检测时还做其他事
就这些捏,到目前为止说的差不多啦,再会啦~
相关文章:

控制欲过强的Linux小进程
控制欲强?视奸?普通人那才叫视奸,您是皇帝,天下大事无一逃过您的耳目,您想看什么就看什么,臣怀疑他在朋友圈私养兵士,囤积枪甲,蓄意谋反,图谋皇位啊! 哈哈哈哈开个玩笑&…...

探讨元宇宙和VR虚拟现实之间的区别
在数字时代,人们对虚拟现实的兴趣与日俱增。在虚拟现实技术的推动下,出现了两个概念:元宇宙和VR虚拟现实。虽然这两个概念都与虚拟现实有关,但它们有着不同的特点和用途。在本文中,我们将探讨元宇宙和VR虚拟现实之间的…...

Docker Desktop安装
0 Preface/Foreward 1 安装 1.1 运行docker安装包 安装完Docker Desktop后,运行Docker Desktop,出现WSL 2安装不完整情况,具体情况如下: 解决方法:旧版 WSL 的手动安装步骤 | Microsoft Learn 也可以直接下载新的安…...

《Towards Black-Box Membership Inference Attack for Diffusion Models》论文笔记
《Towards Black-Box Membership Inference Attack for Diffusion Models》 Abstract 识别艺术品是否用于训练扩散模型的挑战,重点是人工智能生成的艺术品中的成员推断攻击——copyright protection不需要访问内部模型组件的新型黑盒攻击方法展示了在评估 DALL-E …...

vscode调试nextjs前端后端程序、nextjs api接口
最近有一个项目使用了nextjs框架,并且使用nextjs同时实现了前后端,由于之前前后端都是分离的,前端的调试可以通过在代码种添加debugger或者直接在浏览器中打断点实现,现在想调试后端接口,前面的方式就不适用了。故研究…...

《SeTformer Is What You Need for Vision and Language》
会议:AAAI 年份:2024 论文:DDAE: Towards Deep Dynamic Vision BERT Pretraining - AMinerhttps://www.aminer.cn/pub/6602613613fb2c6cf6c387c2/ddae-towards-deep-dynamic-vision-bert-pretraining 摘要 这篇论文介绍了一种新型的变换器…...

[保姆级教程]uniapp安装使用uViewUI教程
文章目录 创建 UniApp 项目下载uView UI下载安装方式步骤 1: 安装 uView UI步骤 2: 查看uView UI是否下载成功步骤 3: 引入 uView 主 JS 库步骤 4: 引入 uView 的全局 SCSS 主题文件步骤 5: 引入 uView 基础样式步骤 6: 配置 easycom 组件模式注意事项 NPM方式步骤 1: 安装 uVi…...

网络安全法规对企业做等保有哪些具体规定?
网络安全法规对企业做等保的具体规定 根据《中华人民共和国网络安全法》,企业作为网络运营者,需要履行网络安全等级保护制度的相关义务,确保网络安全和数据保护。具体规定包括: 网络安全等级保护制度:企业应根据网络安…...

Java开发中超好用Orika属性映射工具
Orika属性映射工具 引入pom依赖 <dependency><groupId>ma.glasnost.orika</groupId><artifactId>orika-core</artifactId><version>1.5.4</version></dependency>上干货 封装的工具类:OriUtilsimport ma.glasnost.orika.Map…...

qt初入门8:下拉框,输入框模糊查询,提示简单了解 (借助QCompleter)
实现一个简单的模糊查询的逻辑,输入框能提示相关项。 主要借助qt的QCompleter 类( Qt 框架中提供的一个用于自动补全和模糊搜索的类),结合一些控件,比如QComboBox和QLineEdit,实现模糊查询的功能。 1&…...

【qt】VS中如何配置Qt环境
https://download.qt.io/official_releases/vsaddin/ 首先需要下载一下vsaddin,上面的是下载的网站. 下载的时候可能会出现下图的情况 说明你下的vsaddin和您的VS版本不匹配,所以你可以多下几个其他版本的vsAddin,一般都是和你VS版本相匹配的才可以,如Vs2022,那就试试vsaddin2…...

对于相同网段的IP,部分无法ping通问题
现象1:在Linux上执行 ping 192.168.1.232,无法ping通 分析1:使用ifconfig查询,联网使用eth0口,只能上网192.168.10.xx网段,需要增加网段 解决方法:使用ip addr 查询,本身只具备10网…...

Unity发布XR中用于worldbuilding的全新电子书
通过身临其境的虚拟领域开始旅程,在维度之间传送,或将数字奇迹与现实世界融合——虚拟现实(VR)和混合现实(MR)的千万种可能性将邀请创作者把他们的想象力带入生活。 Unity发布的最新版综合指南将帮助有抱负的创作者和经验丰富的开发者深入研究和理解构建…...

Vue3相比于Vue2进行了哪些更新
1、响应式原理 vue2 vue2中采用 defineProperty 来劫持整个对象,然后进行深度遍历所有属性,给每个属性添加getter和setter,结合发布订阅模式实现响应式。 存在的问题: 检测不到对象属性的添加和删除数组API方法无法监听到需要对…...

Unity UGUI 之 Slider
本文仅作学习笔记与交流,不作任何商业用途 本文包括但不限于unity官方手册,唐老狮,麦扣教程知识,引用会标记,如有不足还请斧正 1.Slider是什么 滑块,由三部分组成:背景 填充条 手柄 填充条就是…...

这7款高效爬虫工具软件,非常实用!
在当今数据驱动的时代,自动化爬虫工具和软件成为了许多企业和个人获取数据的重要手段。这里会介绍6款功能强大、操作简便的自动化爬虫工具,用好了可以更高效地进行数据采集。 1. 八爪鱼采集器 八爪鱼是一款功能强大的桌面端爬虫软件,主打可…...

【OJ】二叉树相关OJ题
✨✨欢迎大家来到Celia的博客✨✨ 🎉🎉创作不易,请点赞关注,多多支持哦🎉🎉 所属专栏:OJ题 个人主页:Celias blog~ 目录 编辑 单值二叉树 题目描述 OJ-单值二叉树 解题思路 …...

Blender中保存透明图片
在Blender中保存透明图片,主要是通过在渲染设置中调整背景透明度,并选择合适的文件格式来保存图像。以下是一个详细的步骤指南: 一、设置渲染属性 打开Blender并加载你想要渲染的模型。在右侧的属性编辑器中,找到并点击“渲染属…...

MySQL之索引优化
1、在进行查询时,索引列不能是表达式的一部分,也不能是函数的参数,否则无法使用索引 例如下面的查询不能使用 actor_id 列的索引: #这是错误的 SELECT actor_id FROM sakila.actor WHERE actor_id 1 5; 优化方式:…...

Spring Boot 与 Amazon S3:快速上传与下载文件的完整指南
概要 在将 Spring Boot 更新到 3 系列时,由于 javax 需要被替换为 jakarta,因此原先依赖于 javax 的 spring-cloud-starter-aws1 将无法使用(虽然在我本地环境中仍然可以正常工作)。为了确保兼容性,我将依赖关系更改为…...

细节剖析:HTTP与HTTPS在安全性、性能等方面的不同!
HTTPS是现代互联网通信的重要基石,通过加密通信、身份验证和数据完整性保护,为数十亿用户提供了安全可靠的互联网体验。 小编整理了2GB程序员相关资料,关注微信公众号“程序员Style”回复“程序员”免费领取! 1、介绍 随着 HTT…...

MySQL面试篇章——MySQL索引
文章目录 MySQL 索引索引分类索引创建和删除索引的执行过程explain 查看执行计划explain 结果字段分析 索引的底层实现原理B-树B树哈希索引 聚集和非聚集索引MyISAM(\*.MYD,*.MYI)主键索引辅助索引(二级索引) InnoDB&a…...

WSL 2 Oracle Linux 9.1 安装配置
文章目录 环境使用体验安装 Oracle Linux 9.1修改默认存储路径默认 root 用户登录启用 systemd启用 SSH 连接WSL 无法 ping 通宿主机和域名WSL 使用主机代理(测试通过)WSL 常用命令 环境 OS:Win11 24H2 (OS 内部版本26120.1252) wsl --versio…...

MySQL日志文件详解
MySQL中的日志文件是MySQL数据库系统的重要组成部分,它们记录了数据库的运行情况、用户操作、错误信息等,对于数据库的维护、优化、故障排查和恢复都具有重要意义。以下是MySQL中几种主要日志文件的详解: 1. 二进制日志(Binary L…...

MySQL零散拾遗(三)
在mysql中,JOIN ON 和 WHERE 的作用和用法是怎么样的? 在MySQL中,JOIN语句用于将两个或多个表根据指定的关联条件合并成一个新的结果集。JOIN ON和WHERE子句在JOIN语句中扮演着不同的角色,它们的用法和作用如下: JOI…...

鸿蒙 使用 Refresh 实现下拉刷新
import promptAction from ohos.promptActionEntry Component struct Index {Staterefreshing: boolean falseStatelist: number[] Array(20).fill(Date.now())Buildercontent(){Stack(){Row(){LoadingProgress().height(32)Text(正在刷新...).fontSize(16).margin({left:20}…...

【JavaScript 算法】图的遍历:理解图的结构
🔥 个人主页:空白诗 文章目录 一、深度优先搜索(DFS)深度优先搜索的步骤深度优先搜索的JavaScript实现 二、广度优先搜索(BFS)广度优先搜索的步骤 三、应用场景四、总结 图的遍历是图论中的基本操作之一&am…...

Ubuntu 中默认的 root 用户密码
场景:想要切换root用户,发现得输入密码,以为是以前设置过然后一直尝试都是错误【认证失败】最后发现根本没设置过root用户,默认会随机生成root用户的密码😅 Ubuntu 中默认的 root 密码是随机的,即每次开机都…...

Rust编程-高级特性
unsafe:内存不安全 内存安全问题,例如空指针解引用 关键字unsafe来切换到不安全模式,并在被标记后的代码块中使用不安全代码 使用unsafe告诉编译器后面代码安全性自行负责 因为电脑硬件安全问题,必须编写可能不安全的代码 可以将…...

JavaRegexImprove练习(1) (2024.7.22)
ImproveExercise1 package RegexImprove20240722; import java.util.Scanner; public class ImproveExercise {public static void main(String[] args) {Scanner sc new Scanner(System.in);System.out.println("请输入一个字符串");String str sc.nextLine();//…...