进程创建用fork()
#include<stdio.h>
2 #include <unistd.h>
3 int main(){
4 printf(“parent pid:%d\n”,getpid());
5 int a=100;
6 pid_t pid= fork();//复制
7 if(pid<0){
8 return -1;//如果PID 小于0出错
9 }else if(pid==0){
10 printf(“child!!! pid:%d\n”,getpid());//这句话放在子进程之后,子进程返回值为0
11 }else {
12 printf(“parent!!!:%d ----child: %d\n”,getpid(),pid);//getpid
13 //为父进程的PID而pid为返回值返回子进程的PID
14 }
15 printf(“nihaoa! %d\n”,a);
16 return 0;
17 }
通过复制条用进程创建进程
子进程复制的就是父进程的PCB(父子进程数据代码看起来一样)代码共享数据独有
返回值:返回时子进程的PID子进程返回的是0
因为父子进程代码运行一样,所以要通过返回值来分流父子进程
pid_t fork(void)通过复制调用进程创建一个新的进程,
创建子进程的意义:压力分摊/干其他工作
如何分辨子进程:返回值
父进程返回值大于0,返回为子进程的PID
子进程的返回值等于0
进程状态:就绪阻塞运行
//状态转换
#include <unistd.h>
4 #include <stdint.h>
5 int main(){
6 uint64_t a=0;
7 while(1){
8 a++;
9 }
10 return 0;
11 }
运行好后再开一个终端查看操作系统的进程信息
ps -aux |grep status
[chenyongjie@localhost ~]$ ps -aux|grep status
chenyon+ 4838 100 0.0 4208 344 pts/0 R+ 08:32 1:22 ./status
然后 ps -aux | head -1 && ps -aux |grep status//打印头部也就是第一行
ps -aux | head -1为首行
&&是命令连接如果前面命令运行成功那么执行后面的命令
[chenyongjie@localhost ~]$ ps aux |head -1 && ps -aux|grep status
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
chenyon+ 4887 97.1 0.0 4208 344 pts/0 R+ 08:38 0:26 ./status
chenyon+ 4894 0.0 0.0 112724 984 pts/1 S+ 08:38 0:00 grep --color=auto status
可以看到PID为4887然后当前状态为R+
然后在运行的终端ctrl+z
[chenyongjie@localhost linux]$ ./status
^Z
[1]+ 已停止 ./status
然后ps aux |head -1 && ps -aux|grep status会发现状态变为T进程停止什么都不干;
[chenyongjie@localhost ~]$ ps aux |head -1 && ps -aux|grep status
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
chenyon+ 4887 69.6 0.0 4208 344 pts/0 T 08:38 1:57 ./status
chenyon+ 4951 0.0 0.0 112724 988 pts/1 S+ 08:40 0:00 grep --color=auto status
干掉进程conrtl+c 也可以kill
kill 9 加pid强制杀死
linux 下:
运行R,可中断睡眠S;不可终端数目D停止T死亡x,僵死Z
ps -efl看父子进程,ps aux看状态
!!!进程杀不死是什么原因?
僵尸进程:处于僵死状态的进程
!ps重新查看
chenyon+ 5325 2.2 0.0 4208 348 pts/0 S+ 08:52 0:00 ./status
chenyon+ 5326 2.0 0.0 4208 88 pts/0 S+ 08:52 0:00 ./status
可以看到有两个进程在运行
而ps -efl可以看到父进程和子进程
0 S chenyon+ 5387 3328 2 80 0 - 1052 hrtime 08:58 pts/0 00:00:00 ./status
1 S chenyon+ 5388 5387 2 80 0 - 1052 hrtime 08:58 pts/0 00:00:00 ./status
可以看到子进程的PID为5388 然后KILL 5388
那么在看(!ps)就会发现当前状态变成Z了
产生原因:
子进程优先于父进程退出,操作系统检测大退出,通知父进程,但是父进程这时候正在忙其他事,没有关注这个通知,这时候操作系统为了封锁现场,不会释放子进程资源,因为 子进程PCB包含有退出原因,这时候因为既没有运行也没有完全退出因此处于僵死状态,成为僵尸进程
僵尸进程危害:
资源泄漏
如何处理
kill -9 5388强制杀死也杀不死,
处理方式关闭父进程
避免父进程wait()???
孤儿进程:
+代表前台进程没加好就是后台进程,它的父进程退出或者kill子进程会成为后台进程,然后其子进程PID没有变但是它的父进程PPID变成 了1,孤儿进程并不是说没有父进程而是被1号进程领养了,但是此时的孤儿进程可以Kill-9杀死
综上:孤儿进程就是父进程先于子进程退出,父进程退出后,子进程成为后台进程并且父进程成为1号进程
进程优先级:
优先级:决定了资源的有限分配权,就是决定资源优先分配权的等级划分
为什么要有优先级:让操作系统运行的更加合理
操作系统有很多进程每个进程完成操作不同因为功能划分划分为:
交互式进程:与用户相关,大多数处于休眠状态,但是优先级高,一旦有操作有限处理
和批处理进程:在后台批量一直处理某些进程数据,但是对cpu要求并不高
优先级的设置:
ps -efl |grep status
pri就是优先级通eu过数字标明处于睡眠等级但是不能直接修改,可以跟优先级一起的值来修改它,PRI=PRI+NI,可以修改NI就是NICE值,如果一个进程已经运行起来修改优先级 renice -n 10 -p 7635;修改正在运行的进程7635的优先级,pid数字越大优先级越低但是也有范围
切记PRI无法直接设置,但是可以通过设置NI进而调整PRI
renice -n size -p pid 在运行时候设置为:nice -n size ./main
io密集型程序 cpu 密集型程序
设置方法io密集型程序(磁盘读写,调整优先级对其作用不大因为很多时候是在等待读写的过程也就是IO密集型程序对cpu要求不高)但是b对于cpu密集型程序(cpu占有率大)不涉及IO一直数据处理对cpu要求高这时候调整优先级则很明显;
[chenyongjie@localhost ~]$ whereis proc
proc: /usr/share/man/man5/proc.5.gz
找一个系统文件的绝对路径
优先级的概念:
并行:cpu资源足额够,多个程序同时运行
并发:cpu资源不够,多个程序切换运行,同时推进(多个进程都得以推进)
独立性:进程间相互独立
竞争性:狼多肉少,因此狼之间都有竞争性
!!!环境变量:保存系统运行环境参数的变量
作用:设置系统运行环境参数,让变量保存起来当他运行起来更加快
装JDK会设置一个环境变量,是什么东西?电脑属性高级变量–>环境变量都是一些环境变量(都是路径)设置一些参数,eg:path就是放的一些命令,jdk就是一个解释程序就存放在某个指定的路径下(安装路径)如果没有设置环境变量那么就java找不着,但是设置了就会告诉一些用法,
ls能直接运行因为电脑上有一个环境变量叫PATH,然后里面有个bin:以:间隔,这个bin里面就有ls程序,能够执行ls就是因为有PATH这个环境变量的存在,当执行ls时候shell就会在这些路径下找ls的程序找到了就会执行,所以环境变量就是让操作系统运行起来更加方便更加快捷,系统某些参数设置的时候更加有效率.
echo
P
A
T
H
/
u
s
r
/
l
o
c
a
l
/
b
i
n
:
/
u
s
r
/
b
i
n
:
/
u
s
r
/
l
o
c
a
l
/
s
b
i
n
:
/
u
s
r
/
s
b
i
n
:
/
h
o
m
e
/
c
h
e
n
y
o
n
g
j
i
e
/
.
l
o
c
a
l
/
b
i
n
:
/
h
o
m
e
/
c
h
e
n
y
o
n
g
j
i
e
/
b
i
n
比
如
一
个
s
t
a
u
t
s
程
序
不
能
运
行
那
么
可
以
这
样
做
p
w
d
,
找
到
s
t
a
t
u
s
的
绝
对
路
径
,
然
后
设
置
环
境
变
量
PATH /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/chenyongjie/.local/bin:/home/chenyongjie/bin 比如一个stauts程序不能运行那么可以这样做pwd,找到status的绝对路径,然后设置环境变量
PATH/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/chenyongjie/.local/bin:/home/chenyongjie/bin比如一个stauts程序不能运行那么可以这样做pwd,找到status的绝对路径,然后设置环境变量PATH=
P
A
T
H
:
.
.
.
然
后
s
t
a
t
u
s
就
可
以
运
行
了
[
c
h
e
n
y
o
n
g
j
i
e
@
l
o
c
a
l
h
o
s
t
]
PATH:... 然后status就可以运行了 [chenyongjie@localhost ~]
PATH:...然后status就可以运行了[chenyongjie@localhost ] status
bash: status: 未找到命令…
[chenyongjie@localhost ~]$ cd linux/
[chenyongjie@localhost linux]$ pwd
/home/chenyongjie/linux
[chenyongjie@localhost linux]$ PATH=
P
A
T
H
:
/
h
o
m
e
/
c
h
e
n
y
o
n
g
j
i
e
/
l
i
n
u
x
/
[
c
h
e
n
y
o
n
g
j
i
e
@
l
o
c
a
l
h
o
s
t
]
PATH:/home/chenyongjie/linux/ [chenyongjie@localhost ~]
PATH:/home/chenyongjie/linux/[chenyongjie@localhost ] status
nihaoshijie!!![pid=6725]
nihaoshijie!!![pid=6725]
[chenyongjie@localhost linux]$ haoe
haoe
前提一定要保证操作系统没有这个关键字才能
环境变量如何查看:
encho打印一个指定的环境变量的名称来打印内容echo
P
A
T
H
查
看
所
有
的
环
境
变
量
e
n
v
[
c
h
e
n
y
o
n
g
j
i
e
@
l
o
c
a
l
h
o
s
t
l
i
n
u
x
]
PATH 查看所有的环境变量env [chenyongjie@localhost linux]
PATH查看所有的环境变量env[chenyongjie@localhostlinux] env
打印出来所有的:环境变量截图了一部分
XDG_SESSION_ID=8
HOSTNAME=localhost.localdomain
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=192.168.96.1 2425 22
SELINUX_USE_CURRENT_RANGE=
OLDPWD=/home/chenyongjie
SSH_TTY=/dev/pts/1
USER=chenyongjie
当前主机名chenyongje,shell=bin/bash
当前把欧村的历史命令条数为1000HISTSIZE,终端的client192.168.96.1 2425 22,用户为chenyongjie终端号pts1 SSH_TTY=/dev/pts/1
set也可以查看环境变量比env更多
设置环境变量
MYENV=1000
echo $MYENV则1000就打印出来了
但是env|grep MYENV却没有
export MYENV
这个时候就出来了
[chenyongjie@localhost linux]$ MYENV=1000
[chenyongjie@localhost linux]$ echo MYENV
MYENV
[chenyongjie@localhost linux]$ MYENV=999
[chenyongjie@localhost linux]$ echo
M
Y
E
N
V
999
[
c
h
e
n
y
o
n
g
j
i
e
@
l
o
c
a
l
h
o
s
t
l
i
n
u
x
]
MYENV 999 [chenyongjie@localhost linux]
MYENV999[chenyongjie@localhostlinux] env |grep MYENV
[chenyongjie@localhost linux]$ export MYENV
[chenyongjie@localhost linux]$ env |grep MYENV
MYENV=999
export声明一个环境变量
删除一个环境变量 unset MYENV
[chenyongjie@localhost linux]$ unset MYENV
在查看就没有 了包括echo MYENV也没有了
查看:
echo 通过变量名称查看环境变量
env查看所有环境变量
set 查看环境变量以及临时变量
export声明/设置一个环境变量
unset 删除一个环境变量
常见环境变量HOME SHELL
环境变量的全局特性:继承特性
#include <stdio.h>
W> 3 int main(int argc,char argv[],charenv[]){
4 int i=0;
5 for(i=0;env[i]!=NULL;i++){
6 printf(“env[%d]=[%s]\n”,i,env[i]);
7 }
8 return 0;
9
10 }
2yy大写P复制两行数据
然后在命令模式
1s/status/env/g;在makefile将第一行的status替换成env
然后make就全部答应出来了
env[15]=[PWD=/home/chenyongjie/linux]
env[16]=[LANG=zh_CN.utf8]
env[17]=[SELINUX_LEVEL_REQUESTED=]
env[18]=[HISTCONTROL=ignoredups]
env[19]=[SHLVL=1]
env[20]=[HOME=/home/chenyongjie]
env[21]=[LOGNAME=chenyongjie]
法2
extern char *environ;
13 int i;
14 for(i=0;environ[i]!=NULL;i++){
15 printf(“env[%d]=[%s]\n”,i,environ[i]);
16 }
17 return 0;
也可以打印出
法3最长用的getenv(),通过环境变量名称找到环境变量的值
char ptr=getenv(“HOME”);
printf(“HOME”":[%s]\n",ptr);
printf(“HOME:[%s]\n”,getenv(“HOME”));
return 0;
就可以了
shell运行原理:
终端一打开就运行的shell命令,当在输入./status,运行程序,程序加载到内存然后操作系统创建pcb然后内存指针指向数据以及代码的位置,在这之中shell对输入的命令进行解析,shell在获取到./status,直到了运行了什么程序,然后shell解析命令参数,知道了运行status程序并且status程序在当前目录下然后shell创建了运行了一个fork函数就创建了一个子进程也创建了一个pcb然后要运行./status程序,相当于在内存当中把status加载进去然后Pcb指向它就开始运行了,此处shell是个进程./status也是个进程
环境变量的全局特性
echo $MYENV=1000
export MYENV
printf(“MYENV:[%s]\n”,getenv(“MYENV”));
!!!此处也能打印ENV,但是值能针对于一个终端,但是只能算是继承
父子进程传递信息只能通过环境变量来传递信息
环境变量的全局特性:在子进程中获取继承于父进程的环境变量信息
main (int argc ,char argc[],char env[])参数获取
exter char environ全局变量获取
chargetenv(const char env_name)接口获取
程序地址空间
程序里面打印的地址为假的地址
内存的编号,指向内存的一块区域
虚拟地址空间:mm_stuct{
long int size;//当前地址空间有多大
描述各个区域:code_start,起始编号代码段的起始结束
code_end;
data_start;//数据起始结束
data_end;
等(划分十分详细)
}
通过这样的描述方式讲进程所使用的内存描述出来了然后每个变量使用的时候就在指定区域去获取一些地址,地址分配了后如果定义了一个变量真正使用还是通过页表映射对应到物理内存上面刚开始在子进程变量没有发生变化虚拟地址空间是一样的物理空间也是一样的但是当子进程值发生变化时候也就是和父进程的值不一样的时候,为了保证每个进程的独立性操作系统会给子进程重新开辟自己的物理空间,此时的开辟是用到哪开辟到哪哪个变量改变了给子进程重新开辟一块然后将数据拷贝过来这时子进程就拥有自己的内存区域这时父子进程就数据不一样了也是数据独有的由来也就是写时拷贝技术
写时拷贝技术出发点就是节省资源,提高子进程创建效率
队列???内核的进程调度算法
vfork:创建子进程,阻塞父进程
子进程先运行,父进程等到子进程exit退出或者程序替换之后父进程才会运行否则同时运行因为父子进程公用虚拟地址空间会造成调用栈混乱因此阻塞父进程vfork进程如果return退出释放资源会导致父进程混乱或者错误
进程终止
main函数中return 刷新缓冲区释放资源
exit 刷新缓冲区释放资源
_exit 释放资源
返回值:
程序正常退出结果符合预期
程序正常退出结果不符合预期
异常退出
$? 查看进程退出返回值
perror 答应系统调用接口错误原因
strerror(error)将系统调用错误编号解释为字符串原因
进程等待:等待子程序退出
避免产生僵尸进程
因为父进程不知道子进程什么时候退出,因此只能在子进程创建之后调用wait进行进程等待,因为调用wait就是一直在等待子进程退出
wait 接口是一个阻塞函数
阻塞:为了完成某个功能发起调用,如果当前不具备完成条件一直等待直到完成后退出.如果没有子进程退出再一直等待直到有子进程退出
非阻塞:为了完成某个功能发起调用,如果当前不具备完成条件直接保存返回