[Linux]进程控制详解!!(创建、终止、等待、替换)
hello,大家好,这里是bang___bang_,在上两篇中我们讲解了进程的概念、状态和进程地址空间,本篇讲解进程的控制!!包含内容有进程创建、进程等待、进程替换、进程终止!!
附上前2篇文章链接:
Linux——操作系统进程详解!!(建议收藏细品!!)_bang___bang_的博客-CSDN博客
[Linux]环境变量 进程地址空间(虚拟内存与物理内存的关系)_bang___bang_的博客-CSDN博客


目录
1️⃣计算机四个重要概念
2️⃣进程创建
🍙fork函数初识
🍙fork返回值
🍙fork调用失败原因
3️⃣进程终止
🍙进程终止的场景
🍙退出码
🍥查看退出码echo
🍥字符串格式查看错误信息strerror
🍥退出码讲解
🍙进程常见退出方法
🍥_exit函数——系统调用接口
🍥exit函数——C库函数
🍥return退出
4️⃣进程等待
🍙进程等待必要性
🍙进程等待的方法
🍥wait方法
🍥waitpid方法
5️⃣进程程序替换
🍙替换原理
🍙替换函数
🍥execl函数
🍥execv函数
🍥execlp函数
🍥execle函数
🍥execvp函数
🍥execvpe函数
🍥execve函数(系统调用)
1️⃣计算机四个重要概念
✦竞争性:系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
✦独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰
✦并行:多个进程在多个CPU下分别,同时进行运行,这称之为并行
✦并发:多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发
2️⃣进程创建
fork创建子进程,操作系统都做了什么?
fork创建子进程,系统多了一个进程。
进程=内核数据结构+进程代码和数据!
🍙fork函数初识

- 创建子进程:失败返回-1,成功返回子进程PID给父进程,0返回给子进程
进程调用fork,当控制转移到内核中的fork代码后,内核做:
★分配新的内存块和内核数据结构给子进程
★将父进程部分数据结构内容拷贝至子进程
★添加子进程到系统进程列表当中
★fork返回,开始调度器调度
在进程详解篇,我提到过父子进程代码共享。
那么有个问题:是父进程所有的代码子进程都共享呢?还是在fork函数之后的代码才共享?
🌰写一段fork代码看看结果(提示:眼见不一定为实)
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
int main()
{int num=0;int*p=#printf("Begin:pid:%d,&num:%p\n",getpid(),p);pid_t id=fork();if(id<0){perror("fork");}printf("After:pid:%d,fork return %d,&num:%p\n",getpid(),id,p);return 0;
}
根据结果我们发现Begin在子进程并没有执行,但这能表示子进程没有共享父进程的Begin代码吗?
答案是不是的!!!实际上子进程也共享到了父进程的Begin语句,只不过CPU中有个EPI寄存器,他保存了进程的上下文信息,使得子进程以为fork是他的开始,从fork语句后开始执行!!
创建子进程,给子进程分配对应的内核空间结构,必须子进程自己独有,因为进程具有独立性!理论上,子进程也要有自己的代码和数据!可是一般而言,我们创建的子进程没有加载的过程(代码和数据一般是从磁盘上加载到的程序),也就是说,子进程没有自己的代码和数据!所以,子进程只能“使用”父进程的代码和数据!
代码:都是不可被写的,只能读取,所以父子共享!
数据:可能被修改的,所以,必须分离!
🍙fork返回值

★子进程返回0
★父进程返回子进程的pid
★出错返回-1
为什么fork会有2个返回值?是因为写时拷贝!!
在进程地址空间中我有讲解,这里再简单讲解一下!
基于进程的独立性,父子进程的数据必须分离,但是对于只读的数据我们也进行拷贝的话,对内存太过于浪费,所以出现了一种新的技术:写时拷贝技术!
写时拷贝,是一种延时申请技术,可以提高整机内存的使用率。
子进程执行读权限的时候,父子进程页表映射到同一物理内存,当执行写权限时,OS重新拷贝一份数据到物理内存上,同时子进程的页表断开原来的映射关系,映射到拷贝数据的物理地址。
🍙fork调用失败原因
★系统中有太多的进程
★实际用户的进程数超过了限制
3️⃣进程终止
进程终止时,操作系统做了什么?
答:释放进程申请的相关内核数据结构和对应的数据和代码。本质:释放系统资源。
🍙进程终止的场景
✦代码运行完毕,结果正确
✦代码运行完毕,结果不正确
✦代码异常退出
🍙退出码
🍥查看退出码echo
//获取最近一个进程,执行完毕的退出码!
echo $?
问题:main函数返回值的意义是什么?为什么总是0?
并不是总是0,返回值是进程的退出码!0表示进程运行结果正确,非0表示进程运行结果错误。
返回值的意义:返回给上一级进程,用来评判该进程执行结果用的,可以忽略。让上层能根据程序的退出码定位代码出错的原因。非0值有无数个,不同的非0值就可以标识不同的错误原因!!从而给我们的程序在运行结束之后,结果不正确时,方便定位错误的原因细节!
🍥字符串格式查看错误信息strerror
为了方便我们查看对应的错误是什么,C库提供了一个函数strerror,将错误以字符串的形式打印。

🍥退出码讲解
退出码在status参数中!
status并不是按照整数来整体使用的!而是按照bit位的方式,将32个bit位进行划分(位图)
上图是status的低16位示意图。
系统提供了2个宏来获取退出码和退出信号:

WIFEXITED(status) //是否正常退出
WEXITSTATUS(status) //若正常退出,获取退出码
使用:grep -ER 'xxxx' /usr/include 进行查找

进程异常退出,或者崩溃,本质是操作系统通过发送信号杀掉了你的进程!!
🍙进程常见退出方法
🍥_exit函数——系统调用接口

参数:status 定义了进程的终止状态,父进程通过wait来获取该值。
#include<stdio.h>
#include<unistd.h> int main()
{ _exit(-1);
}
将status设为-1,补码为全1,但是只有8位,所以退出码显示为255(1111 1111)
🍥exit函数——C库函数

exit最后也会调用_exit,但在调用前还刷新了缓冲区。
🌰观察_exit和exit的区别:
/*_exit测试*/
#include<stdio.h>
#include<unistd.h> int main()
{ printf("hello"); _exit(0);
}/*exit测试*/
#include<stdio.h>
#include<stdlib.h> int main()
{ printf("hello"); exit(0);
}
printf输出是对stdout标准输出文件写入,stdout文件的缓冲区刷新策略是行刷新,即遇到\n刷新!
测试中没有\n,也就不会刷新缓冲区,也就不会显示hello。
但是通过结果图我们可以看到系统调用_exit没有打印,C库函数exit有打印,也就是说exit还刷新了缓冲区。
🍥return退出
🌰return等同于执行exit
#include<stdio.h> int main()
{ printf("hello"); return 0;
}
现象和exit一样,main返回值当做exit的参数。
4️⃣进程等待
🍙进程等待必要性
🍙进程等待的方法
🍥wait方法

参数:输出型参数,获取子进程退出状态,不关心则可以设置为NULL
返回值:成功,返回被等待进程的pid;失败,则返回-1。
🌰wait系统接口的阻塞式测试:


🍥waitpid方法

pid_ t waitpid(pid_t pid, int *status, int options);
返回值:当正常返回的时候waitpid返回收集到的子进程的进程ID;如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
pid:pid=-1,等待任一个子进程。与wait等效。pid>0.等待其进程ID与pid相等的子进程。
status:输出型参数!WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
options:默认为0,表示阻塞等待WNOHANG(非阻塞等待): 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。waitpid(pid,NULL,0)==wait(NULL)
🌰waitpid系统接口的阻塞式测试:
结果与wait一致。
🌰 等待回收僵尸进程:


🌰waitpid非阻塞式轮询检测测试:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>//非阻塞等待测试代码int main()
{pid_t id=fork();if(id==0){//子进程int cnt=5;while(cnt){printf("我是子进程:%d\n",cnt--);sleep(1);}exit(11); //退出码11,仅用来测试}else{int quit=0;while(!quit){int status=0;pid_t res=waitpid(-1,&status,WNOHANG);//以非阻塞方式等待if(res>0){//等待成功&&子进程退出printf("等待子进程退出成功,退出码:%d\n",WEXITSTATUS(status));quit=1;}else if(res==0){//等待成功&&但子进程并未退出printf("子进程还在运行中,暂时还没有退出,父进程可以再等一等,处理其他事情\n");}else {//等待失败printf("wait失败!\n");quit=1;}sleep(1);}}
}

问题:父进程通过wait/waitpid可以拿到子进程的退出结果,为什么要用wait/waitpid函数呢?直接全局变量不行吗?
答:不行,因为进程具有独立性,数据就要发生写实拷贝,父进程无法拿到正确的退出结果。
问题:既然进程是具有独立性的,进程退出码,不也是子进程的数据吗?父进程又凭什么拿到呢?
答:僵尸进程:至少要保留该进程的PCB信息!task_struct里面保留了任何进程退出时的退出结果信息!!
wait/waitpid本质是读取子进程的task_struct结构中的(退出码:exit_code,退出信号exit_signal)
![]()
5️⃣进程程序替换
之前:fork()之后,父子各自执行父进程代码的一部分;父子代码共享,数据写时拷贝各自一份!
现在:如果子进程就想执行一个全新的程序呢?
想有自己的代码!就需要进程的程序替换,来完成这个功能。
🍙替换原理
🍙替换函数

| 函数名 | 参数格式 | 是否带路径 | 是否使用当前环境变量 |
| execl | 列表 | 不是 | 是 |
| execlp | 列表 | 是 | 是 |
| execle | 列表 | 不是 | 不是,需自己组装环境变量 |
| execv | 数组 | 不是 | 是 |
| execvp | 数组 | 是 | 是 |
| execvpe | 数组 | 是 | 不是,需自己组织环境变量 |
下面我们对各函数进行测试,测试使用ls命令替换程序。模板如下:
🍥execl函数
🌰execl的使用测试:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>int main(int argc,char* argv[],char* env[])
{pid_t id=fork();if(id==0){//子进程printf("子进程开始运行,pid:%d\n",getpid());sleep(3);char* const _argv[]={(char*) "ls",(char*) "-a",(char*) "-l",NULL};//execl函数,传递参数列表execl("/usr/bin/ls","ls","-a","-l",NULL);exit(1);}else{//父进程printf("父进程开始运行,pid:%d\n",getpid());int status=0;pid_t id=waitpid(-1,&status,0);//阻塞等待if(id>0){printf("wait seccess,exit code:%d\n",WEXITSTATUS(status));}}return 0;
}
execl是程序替换,调用该函数成功后,会将当前进程的所有的代码和数据都进行替换,包括以及执行的和没有执行的!(一旦调用成功,后面的所有代码都不会被执行!)
🍥execv函数
🌰execv的使用测试:
//execv函数,传递数组
execv("/usr/bin/ls",_argv);
🍥execlp函数
🌰execlp的使用测试:
//execlp函数,传递文件名(无需路径)和参数列表
execlp("ls","ls","-a","-l",NULL);
🍥execle函数
🌰execle的使用测试:
//execle函数,传递参数列表和组装的环境变量
execle("/usr/bin/ls","ls","-a","-l",NULL,env);
🍥execvp函数
🌰execvp的使用测试:
//使用execvp函数,传递文件名和数组
execvp("ls",_argv);
🍥execvpe函数
🌰execvpe的使用测试:
//execvpe函数,传递文件名,数组,需组织环境变量
execvpe("ls",_argv,env);
🍥execve函数(系统调用)
上面是exec系列的函数,事实上他们都调用execve,只有execve是真正的系统调用

| 函数名 | 参数格式 | 是否带路径 | 是否使用当前环境变量 |
| execve | 数组 | 不是 | 不是,需自己组织环境变量 |
🌰execve的使用测试:
exec.c:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>int main(int argc,char* argv[],char* env[])
{pid_t id=fork();if(id==0){//子进程printf("子进程开始运行,pid:%d\n",getpid());sleep(3);char* const _argv[]={(char*) "ls",(char*) "-a",(char*) "-l",NULL};char* const _argv_mycmd[]={(char*)"mycmd",(char*)"-a",NULL};char* const _env_mycmd[]={(char*)"My_Path=11111",NULL};//系统调用execveexecve("./mycmd",_argv_mycmd,_env_mycmd);exit(1);}else{//父进程printf("父进程开始运行,pid:%d\n",getpid());int status=0;pid_t id=waitpid(-1,&status,0);//阻塞等待if(id>0){printf("wait seccess,exit code:%d\n",WEXITSTATUS(status));}}return 0;
}
mycmd.c:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>int main(int argc,char* argv[])
{if(argc!=2){printf("can not execute!\n");exit(1);}printf("获取环境变量:My_Path:%s\n",getenv("My_Path"));if(strcmp(argv[1],"-a")==0){printf("hello a!\n");}else if(strcmp(argv[1],"-b")==0){printf("hello b!\n");}else{printf("default!\n");}return 0;
}
成功将子进程程序替换为mycmd。
问题:为什么要创建子进程,在子进程中进行进程替换?
——如果不创建,那么我们替换的进程只能是父进程,如果创建了,替换的进程就是子进程,而不影响父进程。为了不想影响父进程,我们想让父进程聚焦在读取数据,解析数据,指派进程执行代码的功能!
文末结语,本篇结合前2篇内容详细讲解了进程控制,包含:进程创建,进程终止,终止码,_exit,进程等待的必要性以及方法(wait,waitpid)阻塞式等待和非阻塞式等待,进程程序替换的替换原理以及6大替换函数和系统调用execve替换子进程程序,图文并茂,使用例子测试代码。
相关文章:
[Linux]进程控制详解!!(创建、终止、等待、替换)
hello,大家好,这里是bang___bang_,在上两篇中我们讲解了进程的概念、状态和进程地址空间,本篇讲解进程的控制!!包含内容有进程创建、进程等待、进程替换、进程终止!! 附上前2篇文章…...
全面适配 | 走近openGauss数据库+鲲鹏欧拉操作系统
引入 全面适配 | openEuler操作系统 openGauss数据库 开篇 1、openEuler欧拉操作系统 百度百科:openEuler是覆盖全场景的创新平台,在引领内核创新,夯实云化基座的基础上,面向计算架构互联总线、存储介质发展新趋势,…...
2023Robocom CAIP省赛 第四题 相对论大师
原题链接: PTA | 程序设计类实验辅助教学平台 题面: 在某个直播间里,观众常常会发送类似这样的弹幕: 鱼越大,鱼刺越大;鱼刺越大,肉越少;肉越少,鱼越小;所以鱼…...
【TypeScript】TS入门级基础学习(一)
【TypeScript】TS入门级基础学习(一) 一、前言 TypeScript 是一种用于应用程序规模的 JavaScript 语言。 TypeScript 向 JavaScript 添加了可选类型,支持用于任何浏览器、任何主机、任何操作系统的大规模 JavaScript 应用程序的工具。 Type…...
jenkins执行jmeter时,报Begin size 1 is not equal to fixed size 5
jenkins执行jmeter脚本的时候一直提示如下错误: Tidying up ... Fri Jul 28 17:03:53 CST 2023 (1690535033178) Error generating the report: org.apache.jmeter.report.dashboard.GenerationException: Error while processing samples: Consumer failed wi…...
在 “小小容器” WasmEdge 里运行小小羊驼 llama 2
昨天,特斯拉前 AI 总监、OpenAI 联合创始人 Andrej Karpathy 开源了 llama2.c 。 只用 500 行纯 C 语言就能训练和推理 llama 2 模型的框架,没有任何繁杂的 python 依赖。这个项目一推出就受到大家的追捧,24 小时内 GitHub 收获 4000 颗星&am…...
【C#】async和await 续
前言 在文章《async和await》中,我们观察到了一下客观的规律,但是没有讲到本质,而且还遗留了一个问题: 这篇文章中,我们继续看看这个问题如何解决! 我们再看看之前写的代码: static public void TestWait2() {var t…...
【Matlab】基于粒子群优化算法优化BP神经网络的数据回归预测(Excel可直接替换数据)
【Matlab】基于粒子群优化算法优化 BP 神经网络的数据回归预测(Excel可直接替换数据) 1.模型原理2.数学公式3.文件结构4.Excel数据5.分块代码5.1 fun.m5.2 main.m6.完整代码6.1 fun.m6.2 main.m7.运行结果1.模型原理 基于粒子群优化算法(Particle Swarm Optimization, PSO)…...
QPainter绘制雷达界面
文章目录 功能实现定义的结构体定义的函数效果图gitee源码链接 功能实现 相较于上一版,这一版添加的功能有: 1、自适应窗口 2、扫描方式(圆周扫描、扇形扫描(指定起始角度和结束角度)) 3、扫描方向&#x…...
flutter:BottomNavigationBar和TabBar
区别 BottomNavigationBarr和TabBar都是用于创建导航栏的组件,但它们有一些区别。 位置不同:BottomNavigationBar通常位于屏幕底部,用于主要导航;而TabBar通常位于屏幕顶部或底部,用于切换不同的视图或页面。 样式不…...
【图论】Prim算法
一.介绍 Prim算法是一种用于解决最小生成树问题的贪心算法。最小生成树问题是指在一个连通无向图中找到一个生成树,使得树中所有边的权重之和最小。 Prim算法的基本思想是从一个起始顶点开始,逐步扩展生成树,直到覆盖所有顶点。具体步骤如下…...
第九十二回 在Flutter中解析JSON数据
文章目录 概念介绍解析方法convert库插件工具 示例代码经验总结 我们在上一章回中介绍了"对dio库进行封装"相关的内容,本章回中将介绍 如何在Flutter中解析JSON数据.闲话休提,让我们一起Talk Flutter吧。 概念介绍 我们在前面章回中介绍了通…...
银河麒麟安装mysql数据库(mariadb)-银河麒麟安装JDK-银河麒麟安装nginx(附安装包)
银河麒麟离线全套安装教程(手把手教程) 1.银河麒麟服务器系统安装mysql数据库(mariadb) 2.银河麒麟桌面系统安装mysql数据库(mariadb) 3.银河麒麟服务器系统安装JDK 4.银河麒麟桌面系统安装JDK 5.银河麒麟…...
文件上传
js绕过 打开网页尝试上传一句话木马,发现只能上传图片文件 审计源代码,发现使用一个checkfile函数js对文件类型进行了屏蔽 于是我们修改网页代码,去除返回值的检查函数 checkFile() 上传成功,使用蚁剑连接 连接成功 .htaccess绕…...
tinkerCAD案例:22. Backpack Zipper Pull 背包拉链头
tinkerCAD案例:21. Custom Stamp 定制印章 原文 tinkerCAD案例:22. Backpack Zipper Pull 背包拉链头 Lesson Overview: 课程概述: Now we’re going to make a zipper pull! 现在我们要做一个拉链头! Your backpack, howev…...
Unity 性能优化四:UI耗时函数、资源加载、卸载API
UI耗时函数 1.1 Canvas.SendWillRenderCanvases 这个函数是由于自身UI的更新,产生的耗时 1. 这里更新的是vertex 属性,比如 color、tangent、position、uv,修改recttransform的position、scale,rotation并不会导致顶点属性改变…...
【Linux】用户相关内容
如果命令ll 出现以上信息,UID为具体的数字,代表之前UID为502的用户被删除了。 更改目录或文件所属用户和所属组 在Linux中,创建一个文件时,该文件的拥有者都是创建该文件的用户。 更改所属用户 chown 用户名 文件名/目录名 更…...
基于多场景的考虑虑热网网损的太阳能消纳能力评估研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
【动态规划part10】| 121.买卖股票的最佳时机、122.买卖股票的最佳时机II
目录 🎈LeetCode121. 买卖股票的最佳时机 🎈LeetCode122.买卖股票的最佳时机II 🎈LeetCode121. 买卖股票的最佳时机 链接:121.买卖股票的最佳时机 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定…...
java 页面html常用写法总结
(注意:本文章默认base html中已经引入bootstrap.min.css、style.css等css样式) input :输入标签 <#input required"必填" id"cycle" name"周期" underline"true" style"width:75%" itype&quo…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
