关键词:
今天是中秋节,祝各位小伙伴中秋节快乐,记得吃月饼吖
图片来自网络,侵联删
Linux进程基本操作
1.进程基本概念
在Linux中进程信息被保存在task_struct(PCB)
2.查看进程的方法
ps
ps aux | greap myproc
ls /proc
3.创建进程
fork():创建一个子进程
#include<iostream>
#include<unistd.h>
using namespace std;
int main()
fork();
while(1)
printf("hehe\\n");
return 0;
fork之前的代码,被父进程执行,fork之后的代码,父子都可以执行
fork之后,父子进程代码共享
fork之后,父子进行那个先运行不确定,取决于操作系统调度算法
fork函数会有两次返回值,给父进程返回子进程pid,给子进程返回0
6 pid_t id=fork();
7 if(id==0)
8
9 while(1)
10
11 printf("我是子进程\\n");
12 sleep(1);
13
14
15 else if(id>0)
16
17 while(1)
18
19 printf("父进程\\n");
20 sleep(2);
21
22
23 else
24
25 printf("进程创建失败\\n");
26
27 return 0
结果:父子进程同时执行
4.进程的状态
进程状态------>数据化-------->进程数据被保存到tack_struct中
进程主要有以下几种状态:
R状态:
可以同时存在多个R状态的进程
R状态的进程不一定是正在运行的,表示随时可以调用该进程
系统中所有处于R状态的进程都会被连接起来形成调度队列(run_queue)
S状态:休眠状态(浅度睡眠)通常用来等待某种事件发生,随时可以被唤醒,也可以被杀掉
//休眠状态
#include<stdio.h>
#include<unistd.h>
int main()
printf("I am Running\\n");
sleep(10000000);
printf("Ending\\n");
return 0;
D状态:深度睡眠状态,D状态没有办法模拟,表示该进程不会被杀掉,即便是操作系统,除非重启杀掉,或者主动醒来
T状态:将进程进行暂停
如上图所示,摁下19sigstop即可暂停进程
X状态:死亡进程
Z状态:僵尸状态
进程退出,在操作系统层面,曾经申请的资源,并不是被立即释放,而是要暂存一段事件,供OS(父进程)进行读取,,而父进程没有读取,叫做僵尸状态
为什么要有僵尸进程:
进程创建的目的:完成某种工作
当任务完成的时候,调用方应该指导任务完成得怎么样
(除非不关心)
sjw@iZ2zedu4njy79sqivntvprZ test_9_11]$ cat test.c
#include<stdio.h>
#include<unistd.h>
int main()
printf("I am Running\\n");
sleep(10000000);
printf("Ending\\n");
return 20;
[sjw@iZ2zedu4njy79sqivntvprZ test_9_11]$ echo $?//查看进程码,查看最近一次进程退出时得进程码(如返回值return 0等)
//进程退出时,进程信息(退出码)是会被暂时保存起来的,相关信息被保存到task_struct,此时,该task_struct相关数据不应该被释放掉 Z
当有进程来读取信息时,task_struct被释放
如何读取信息:进程wait
进程退出的信息(退出码)会被暂时保存起来
保存在task_struct中,如果没有人读取,此时,task_struct相关数据不应该被释放
模拟僵尸状态:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
pid_t id=fork();
if(id==0)
int count=5;
while(count)
printf("I am child, pid:%d, ppid:%d, count:%d\\n",getpid(),getppid(),count--);
sleep(1);
printf("child exit......\\n");
exit(-1);
else if(id>0)
while(1)
printf("I am father,pid:%d, ppid:%d\\n",getpid(),getppid());
sleep(1);
else
printf("fork fail\\n");
return 0;
[sjw@iZ2zedu4njy79sqivntvprZ test_9_11]$ make clean
rm -rf *.o myproc
[sjw@iZ2zedu4njy79sqivntvprZ test_9_11]$ make
gcc -c test.c -o test.o
gcc -o myproc test.o
[sjw@iZ2zedu4njy79sqivntvprZ test_9_11]$ ./myproc
I am father,pid:9259, ppid:308
I am child, pid:9260, ppid:9259, count:5
I am father,pid:9259, ppid:308
I am child, pid:9260, ppid:9259, count:4
I am father,pid:9259, ppid:308
I am child, pid:9260, ppid:9259, count:3
I am father,pid:9259, ppid:308
I am child, pid:9260, ppid:9259, count:2
I am father,pid:9259, ppid:308
I am child, pid:9260, ppid:9259, count:1
I am father,pid:9259, ppid:308
child exit......
I am father,pid:9259, ppid:308
I am father,pid:9259, ppid:308
I am father,pid:9259, ppid:308
I am father,pid:9259, ppid:308
I am father,pid:9259, ppid:308
^Z
然后在另外一个窗口输入以下监控脚本:
while :; do ps aux | head -1 && ps aux | grep myproc|grep -v grep;echo "#############################"; sleep 1; done
刚开始运行时,二者都是S状态,到子进程运行完毕退出进行时,子进程编程僵尸进程
僵尸进程的危害:
造成内存浪费
造成内存泄漏
孤儿进程
Linux中,进程关系,主要是父子关系,
孤儿进程:父进程退出,子进程还在运行
孤儿进行会立即被系统领养(操作系统:1号进程Init)
监控脚本:
while :; do ps axj | head -1 && ps axj | grep myproc|grep -v grep;echo "#############################"; sleep 1; done
#include<stdio.h>
#include<stdlib.h>
#include<unstd.h>
int main()
pid_t id=fork();
if(id==0)
while(1)
printf("I am child,pid:%d,ppid:%d\\n",getpid(),getppid());
sleep(1);
else if(id>0)
int count=5;
while(count)
printf("I am father,pid:%d,ppid:%d,count:%d\\n",getpid(),getppid(),count--);
exit(-1);
return 0;
查看进程:
ps aux |grep Mytest
进程是能够知道自己当前所处的工作目录的
5.进程的优先级
cpu分配资源的先后顺序,即是进程的优先级,优先级越高说明进程被执行的越早
在Linux下输入:
ps -l
出现如上图所示的结果,有几个内容需要我们关注一下:
UID:代表执行者的身份
PID:当前进程的代号
PPID:父进程的代号
PRI:代表进程的优先级,该数字越低,代表进程的优先级越高,被执行的越早(默认该值为80)
NI:代表进程的nice值
NI与PRI的关系:
PRI用来表示进程的优先级,该值越低,代表进程的优先级越高,被执行的越早,该值默认为80,而NI用来改变进程的优先级,NI的取值范围为-2019,PRI(new)=PRI(old)+NI,也就是说我们通过修改NI的值来改变进程的优先级,那么被修改后的进程优先级PRI的取值范围为6099,60代表优先级最高的,99代表优先级最低(ps:每次修改PRI后再次修改时PRI默认为80,在80的基础上进行修改)
修改进程优先级的方法:
top命令--->输入r--->输入想要修改的进程的pid--->输入NI值--->q保存退出
如上图所示我们将上面的进程NI修改为20,而PRI变为60,即最高优先级
其它概念:
独立性:多个进程独自运行,独自享受各种资源,多个进程之间互不干扰
并行:多个进程在多个CPU上分别,同时进行运行
并发:多个进程在一个CPU下采用进程切换的方式,在一段时间内,让多个进程得以推进,称为并发
6.环境变量
环境变量一般使之操作系统中用来指定运行环境得一些参数
如:编写c/c++代码时,在连接的时候,从来不知道我们所连接的动态静态库在哪里,但是照样链接得动,就是相关环境变量帮助环境变量进行查找
常见环境变量
PATH:指定当前搜索路径
HOME:指定用户的主工作目录(即用户登录到LInux系统中时,默认的目录)
SHELL:当前Shell,它的值通常为/bin/bash
查看环境变量的方法
echo $NAME//NAME:你的环境变量名称
我们执行mpproc时前面必须加./,而执行ls之类的却不用加,就是因为ls进行了环境变量的配置,我们也可以进行配置,使之向ls一样直接执行
sudo cp -f mpproc /usr/bin
//直接将我们的可执行程序mpproc复制到/usr/bin目录下,但是这种方法不推荐,因为以后如果同名的或者该目录下文件过多可能会造成误删
这样我们就可以像ls一样执行mpproc,除了这种方式之外还有一个更推荐的方法
首先我们先删除这次的配置:
sudo rm -rf /usr/bin/mpproc
//注意不要直接把bin目录直接给删了
这样我们就删除了上次的配置,比较推荐的是下面这种方法,这种写法当我们退出服务器后路劲会自动消除:
export PATH=$PATH:/home/sjw/Linux_Learning/test_9_17
//直接将路径设置到环境变量当中去
//export:设置环境变量
查看PATH:
echo $PATH
查看HOME:
echo $HOME
查看SHELL:
echo $SHELL
显示当前所有的环境变量
env
set:显示本地系统中所有的环境变量
export :设置自己的环境变量
export myvalue=100
如上所示我们设置自己的环境变量并进行查看
unset:取消自己设置的环境变量
unset myvalue
//取消刚刚设置的环境变量
6.环境变量的组织方式
每个程序都会收到一张环境表,环境表是一个字符指针数组,每个指针指向一个以‘\\0’结尾的环境变量字符
这里我们以c/c++程序为例:
所有的c/c++程序从main函数开始执行,main函数是没有参数的,但实际上main是有参数的
int main(int argc,char*argc[],char*envp[])
//argc用来统计命令行参数
//argc是一个字符指针数组,里面每一个都是字符型的指针,指向命令行参数
//envp也是一个字符指针数组,里面每一个都是字符型的指针,指向环境变量信
//息,而环境变量信息也是通过这样传递给一个函数的
什么是命令行参数,下面我来带大家演示一下
#include<stdio.h>
#include<string.h>
int main(int argc, char*argv[],char*envp[])
for(int i=0;i<argc;i++)
printf("%s\\n",argv[i]);
if(strcmp(argv[1],"-a")==0)
printf("hello world\\n");
else
printf("哈哈\\n");
gcc test.c -o Mytest -std=c99
./myproc -a
这次我们使main带参数,然后进行编译,链接,在最后执行时我们在命令行上输入 ./Mytest -a
这时argv就发挥了作用,用来存储这两个命令行参数,argc用来记录命令行参数的个数,利用这个命令行参数我们可以在刚开始时就进行判断进行分支语句的执行
再比如:
#include<stdio.h>
#include<string.h>
int main(int argc, char*argv[],char*envp[])
printf("argc:%d\\n",argc);
for(int i=0;i<argc;i++)
printf("argv[%d]:%s\\n",i,argv[i]);
return 0;
如上图所示,即将命令行参数进行了保存
接下来我们来聊一聊envp,它也是一个字符指针数组,指向系统的环境变量信息,通过envp我们可以调用到系统的环境变量信息
#include<stdio.h>
#include<string.h>
int main(int argc, char*argv[],char*envp[])
int i=0;
while(envp[i])
printf("envp[%d]:%s\\n",i,envp[i]);
i++;
return 0;
//envp以'\\0'进行结尾
仔细观察就会发现这和上面利用env命令查看到的系统环境变量信息是一致的
在Windows中也存在命令行参数,也可以通过envp来获取系统环境变量信息
//打印Windows下环境变量的信息
#include<stdio.h>
//命令行参数的写法
int main(int argc,char*argv[],char*envp[])
int i = 0;
while (envp[i])
printf("Windows:envp[%d]:%s\\n", i, envp[i]);
i++;
return 0;
如上所示即为Windows下的环境变量信息,同学名还可以在自己的电脑上试一试
环境变量是一个系统级别的全局变量,更本原因是bash之下所有的进程都可以获取
通过系统函数调用查看环境变量
getenv(“NAME”)//NAME为环境变量名称
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(int argc, char*argv[],char*envp[])
//显示PATH环境变量名称
printf("%s",getenv("PATH"));
return 0;
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/type>
//定义全局变量
int g_val=100;
int main(int argc,char*argv[],char*envp[])
pid_t id=fork();
if(id==0)
//在子进程中改变这个全局变量,观察父进程中的全局变量是否发生变化
g_val=200;
printf("child:pid:%d,ppid:%d,g_val:%d,&g_val:%p\\n",getpid(),getppid(),g_val,&g_val);
else
sleep(2);
printf("father:pid:%d,ppid:%d,g_val:%d,&g_val:%p\\n",getpid(),getppid(),g_val,&g_val);
sleep(1);
如上所示,我们在上面代码中定义了一个全局变量g_val,而我们在子进程中改变了g_val的值为200,但是在父进程中g_val的值仍然为100,而且两个进程中g_val的地址是一样的
证明:该地址不是物理地址,而是虚拟地址
是语言层面上见到的地址而不是物理地址
我们在c/c++语言所见到的地址都是虚拟地址,物理地址一般看不到,由操作系统统一进行管理
OS(操作系统)负责将虚拟地址转化为物理地址
每一个进程都有一个进程地址空间,都有一个映射列表
子进程的写入,不会影响父进程,进程之间具有独立性,不会互相影响
写的时候单独拷贝一块空间,数据层面上发生了分离
今天是中秋节,祝各位小伙伴节日快乐,也感谢大家的收藏,评论,转发,期待下次再见
To Be Continued…
建议收藏|熬夜爆肝万字文带你了解dom,文末有彩蛋嗷!!!!✨✨✨(代码片段)
感激相遇你好我是阿ken作者:请叫我阿ken链接:请叫我阿ken主页链接来源:CSDN著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。🌊🌈关于前言:文章部分内容及图片出自网... 查看详情
建议收藏|熬夜爆肝万字文带你了解dom,文末有彩蛋嗷!!!!✨✨✨(代码片段)
感激相遇你好我是阿ken作者:请叫我阿ken链接:请叫我阿ken主页链接来源:CSDN著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。🌊🌈关于前言:文章部分内容及图片出自网... 查看详情
❤️大学三年沉淀,把我的学习经验分享给你,爆肝万字带你走进编程世界!❤️(代码片段)
Hello,大家好,我是Alex。时光匆匆,暑假过的很快,转眼又到了大学的开学季,我也是又混进了我们学院的新生群,发现大家对计算机充满着迷之向往,啊哈哈哈,不过没有人带着入门还是很容易... 查看详情
熬夜爆肝万字c#基础入门大总结建议收藏(代码片段)
往期文章分享点击跳转=>熬夜再战Android从青铜到王者-UI组件快速搭建App界面点击跳转=>熬夜再战Android从青铜到王者-几个适配方案点击跳转=>熬夜再战Android从青铜到王者-开发效率插件篇点击跳转=>Unity粒子特... 查看详情
(大厂必备)厂长熬夜爆肝万字之多线程高并发juc编程⭐学妹已收藏(代码片段)
🔥(大厂必备)厂长熬夜爆肝万字之多线程高并发JUC编程(一)⭐学妹已收藏❤️大家好,我是java厂长,今天带你们体验一把多线程高并发的面试高频!❤️关于作者作者介绍🍓博客主页:作者主页🍓... 查看详情
(大厂必备)厂长熬夜爆肝万字之多线程高并发juc编程⭐学妹已收藏(代码片段)
🔥(大厂必备)厂长熬夜爆肝万字之多线程高并发JUC编程(二)⭐学妹已收藏❤️大家好,我是java厂长,今天再次带你们体验一把多线程高并发的面试高频!❤️关于作者作者介绍🍓博客主页:作者主页... 查看详情
❤️爆肝万字整理的综合架构web服务之nginx详解❤️,附建议收藏(代码片段)
文章目录nginx服务配置详细介绍关于作者前言一、nginxweb入门简介1.1什么是nginx1.2常见的网站服务1.3nginx网站服务特点1.4网站页面访问原理二、nginx服务部署安装2.1实验环境2.2YUM安装2.3源码编译安装2.4nginx重要文件目录结构2.5虚拟主... 查看详情
❤️爆肝万字!一文最全总结之spring从入门到入土❤️(建议收藏)(代码片段)
文章目录最新更新前言1.Spring概述1.1介绍2.IoC入门2.1什么是IoC2.2IoC入门案例1(基础案例)2.3IoC入门案例2(依赖注入)2.4IoC入门案例3(面向接口编程)2.5IoC入门案例4(整合JUnit4)3.IoC详解3.1Bean的创建... 查看详情
❤️爆肝万字!一文最全总结之spring从入门到入土❤️(建议收藏)(代码片段)
文章目录前言1.Spring概述1.1介绍2.IoC入门2.1什么是IoC2.2IoC入门案例1(基础案例)2.3IoC入门案例2(依赖注入)2.4IoC入门案例3(面向接口编程)2.5IoC入门案例4(整合JUnit4)3.IoC详解3.1Bean的创建3.2依赖注... 查看详情
pythonopencv实战画图——这次一定能行!爆肝万字,建议点赞收藏~❤️❤️❤️(代码片段)
📢📢📢📣📣📣🌻🌻🌻Hello,大家好我叫是Dream呀,一个有趣的Python博主,小白一枚,多多关照😜😜😜🏅🏅 查看详情
☀️~算法系列之爆肝万字总结七种查找算法,持续补充更新中,建议收藏~☀️(代码片段)
🍅作者主页:Roninaxious🍅欢迎点赞👍收藏⭐留言📝🍅话不多说🍁开卷!🚢顺序查找算法🚢二分查找算法💥优化二分查找算法🚢插值查找算法🚢斐波那契查找算法🚢顺序... 查看详情
❤爆肝万字手把手教你springboot+mybatis+jquery+html5从0开始写网页一学就会!(内附源码)❤(代码片段)
今天带给大家的是SpringBoot+MyBatis+jQuery+HTML5+CSS简单实现前后端交互,保证干货满满,看完你就可以动手写你自己的程序!首先得需要你创建一个SpringBoot项目,具体怎么创建这里久不多说啦。其次,... 查看详情
☀️~爆肝万字总结递归~❤️玩转算法系列之我如何才能掌握递归解题的能力❤️~十大经典问题助你突破极限~☀️(代码片段)
🍅作者主页:Roninaxious🍅欢迎点赞👍收藏⭐留言📝🚢前言🎐何为递归递归顾名思义就是´递´和´归´👀所谓的‘递’也就是“向下递去”,这个问题可以分解为若干个且形式相同的子问题... 查看详情
熬夜爆肝万字c#基础入门大总结建议收藏(代码片段)
往期文章分享点击跳转=>熬夜再战Android从青铜到王者-UI组件快速搭建App界面点击跳转=>熬夜再战Android从青铜到王者-几个适配方案点击跳转=>熬夜再战Android从青铜到王者-开发效率插件篇点击跳转=>Unity粒子特... 查看详情
万字长文带你还原进程和线程(代码片段)
这是Java建设者的第66篇原创文章我们平常说的进程和线程更多的是基于编程语言的角度来说的,那么你真的了解什么是线程和进程吗?那么我们就从操作系统的角度来了解一下什么是进程和线程。进程操作系统中最核心的概念就... 查看详情
linux疑难杂症解决方案100篇(十五)-万字长文带你深入linux内核学习:环境搭建和内核编译
一、linux内核学习之一:环境搭建--安装Debian7.3本系列文章假设读者已对linux有一定的了解,其实学习linux内核不需要有很深的关于linux的知识,只需要了解以下内容:linux基础知识及基本shell命令;现代操作系统的基本概念;C语言... 查看详情
万字长文带你还原进程和线程(代码片段)
我们平常说的进程和线程更多的是基于编程语言的角度来说的,那么你真的了解什么是线程和进程吗?那么我们就从操作系统的角度来了解一下什么是进程和线程。进程操作系统中最核心的概念就是进程,进程是对正在运行中的... 查看详情
linux疑难杂症解决方案100篇(十五)-万字长文带你深入linux内核学习:环境搭建和内核编译
一、linux内核学习之一:环境搭建--安装Debian7.3本系列文章假设读者已对linux有一定的了解,其实学习linux内核不需要有很深的关于linux的知识,只需要了解以下内容:linux基础知识及基本shell命令;现代操作系统的基本概念;C语言... 查看详情