1、什么是进程?
进程就是一个PCB(struct task_struct ),是一个运行中的程序的描述,通过描述信息中的内存指针能够找到内存中运行的程序代码以及数据,并且通过上下文数据可以保存程序调度切换时正在处理的数据,以及通过程序计数器保存进程切换时程序即将执行的下一步指令等等,通过这些描述信息实现控制一个程序的运行,因此对于操作系统来说进程就是一个PCB。
进程在操作系统中的调度切换运行的,每个进程都有一个CPU时间片(一个进程在CPU上运行的时间段),在CPU上时间片运行完毕后则切换下一个进程----CPU分时机制
2、进程的查看(先让系统运行一个loop程序)****
2.1 ps -ef :查看所有进程信息
grep—通过管道匹配文件名,heah -n 1 —打印格式行
UID | PID | PPID | C | STIME | TTY | TIME | CMD |
---|---|---|---|---|---|---|---|
拥有该程序的用户名 | 当前进程ID | 父进程ID | CPU使用的资源百分比 | 系统启动时间 | 登入者的终端机位置 | 使用掉的CPU时间 | 命令的名称和参数 |
2.2 ps -aux :查看进程详细信息
其使用和ps -ef一致
USER | PID | %CPU | %MEM | VSZ | RSS | TTY | STAT | START | TIME | COMMAND |
---|---|---|---|---|---|---|---|---|---|---|
拥有该程序的用户名 | 当前进程ID | 进程占用CPU百分比 | 进程占用内存百分比 | 进程占用虚存存容量(KB) | 进程占用固定内存容量(KB) | 登入者的终端机位置 | 进程状态 | 进程启动时间 | 使用掉的CPU时间 | 命令的名称和参数 |
3、进程状态
粗略分类,大概有三种状态:
1、运行状态:该进程已经拿到时间片,正在运行程序。
2、就绪状态:该进程处于就绪队列,已经具备除CPU以外的所有资源,只要拿到时间片就能直接运行。
3、阻塞状态:该进程由于某种事件(IO处理,时间片结束,需求资源不足等等)导致进程难以继续运行下去,加入阻塞队列,等待条件满足,在将其加入就绪队列,等待操作系统调度。
在Linux操作系统下可细分为下面几种:
3.1、可执行状态R(task_running):正在运行或就绪状态
//run.c
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4
5 int main()
6 {
7 int i;
8 while(1)
9 {
10 i++; //一直进行CPU操作
11 }
12 return 0;
13 }
3.2、可中断休眠状态S(task_interruptible):
该进程状态是因等待某个事件的反生(比如等待信号量),而被挂起的状态。该进程被放在等待队列中,当这些等待事件满足后,从该等待队列中唤醒一个或多个进程。一般机器由于CPU只有几个,而进程一般会有几十上百甚至更多,所以大多数进程处于该状态。
//sleep.c
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4
5 int main()
6 {
7 while(1)
8 {
9 printf("nihaoya~~~\n"); //一直进行IO操作
10 }
11 return 0;
12 }
3. 3、不可中断休眠状态D(task_uninterruptible):
该进程状态通常是在等待IO(磁盘IO,网络IO,其他外设IO)时间过长而被设置的一种状态。此状态类似于可中断休眠状态,但是该进程是不可以被中断的(包括kill,kill -9,kill -15),中断指的是进程不响应异步信号,可通过reboot(命令重启机器)。
4.4、暂停状态或跟踪状态T(task_stopped or task_tracked):
该状态是因向该进程发送了一个sigstop信号,从而进入task_stopped状态(除非是不可中断休眠状态,不响应信号)。向进程发送一个sigcont信号,可以让其从task_stopped状态恢复为task_running状态。
task_track状态是指进程处于暂停状态,等待跟踪该进程并对其操作的状态。比如在gdb中队被跟踪的进程打一个断点进程该断点停下来就处于task_track状态,其他时候,被跟踪的进城还是处于前面的状态。task_track不能被sigcont唤醒,只能等到调试进程通过ptrace系统调用执行ptrace_cont、ptrace_detach等操作,或者调试退出,进程才能恢复task_running状态。
5.5、退出状态Z(task_dead - exit_zombie):
进程变成僵尸进程的状态。
僵尸进程:是一种已经结束的进程,但是没有j将进程的task_struct从进程列表中删除,太多僵尸进程会导致进程表满,导致系统奔溃,但不占用其他系统资源。
产生原因:子进程在退出时,内核会给其父进程返送一个SIGCHLD,通知父进程来释放子进程的资源,父进程则会通过wait系列的接口来等待子进程的退出,并获取它的退出信息,然后wait系列的接口会顺便将子进程的task_struct释放掉。
5.5.1、僵尸进程:子进程退出后,父进程未接收到子进程退出信息,子进程变僵尸进程。
//zombie.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
printf("**************%d\n",getpid());
pid_t pid = fork();
if(pid < 0)
{
perror("fork error\n");
return -1;
}
else if(pid == 0)
{
//这里是子进程运行,fork返回值为0
printf("子进程pid = %d\n",getpid());
sleep(5);
exit(0);//子进程退出,父进程未等待,子进程变成僵尸进程。
}
else if(pid > 0)
{
//这里是父进程运行,fork返回值为子进程的PID
printf("父进程pid = %d\n",getpid());
}
//以下代码父子进程都可以运行得到
while(1)
{
printf("-------------%d\n",getpid());
sleep(1);
}
return 0;
}
5.5.2、孤儿进程,父进程先于子进程退出
//orphan.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t pid = fork();
if(pid < 0)
{
perror("fork error\n");
}
else if(pid == 0)
{
printf("子进程[%d]\n",getpid());
}
else if(pid > 0)
{
printf("父进程[%d]\n",getpid());
sleep(5);
exit(0);//父进程先于子进程退出,子进程变成孤儿进程
}
while(1)
{
printf("进程号[%d]\n",getpid());
sleep(1);
}
return 0;
}
ps -axu查看变化,父进程退出,子进程状态由S+(前台进程)变成S(后台进程)。
使用ps -ef 查看,子进程的父进程的 ppid 由先前的 5129 变成了 1 (init进程)
init 进程:Linux操作系统启动后,第一个被创建的用户态进程。
①执行系统初始化脚本,创建一系列进程; ②为孤儿进程收尸。
5.5.3、守护进程/精灵进程:
特殊的孤儿进程,脱离终端和会话,运行在后台。
守护进程详解
6、进程优先级
决定CPU调度进程的优先级别,让操作系统更加良好的运行。
PRI = PRI + NI (PRI值越小优先级越高) PRI(priority id 不可直接修改,通过NI修改,NI(-20 —19))
sudo renice -n [NI] -p [PID]
PRI只影响CPU密集型程序,不对IO密集型程序影响。
7、环境变量
用于存储系统运行环境参数的变量,是系统的参数配置更加灵活。
7.1 env —查看所有的环境变量
set —查看所有变量
例如:ls 是一个程序,直接键盘输入ls就可运行这个程序,但要是运行一个普通程序,比如zombie,就要./zombie。这是因为ls这个命令程序存放在默认搜索PATH路径下。
7.2、export—设置环境变量
unset—删除一个变量
export PATH=${PATH}:./ ---将./加入默认搜索路径下
7.3、向进程传递参数
(1main函数第三个参数—所有的环境变量
(2)extern char** environ—所有的环境变量
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc, char* argv[],char* env[])
{
int i;
extern char** environ;//声明外部定义的环境变量
for(i = 0;environ[i] != NULL;i++)
{
printf("environ[%d]=[%s]\n",i,environ[i]);
}
return 0;
}
(3)char getenv(const char* name);----通过环境变量名称获取内容
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc, char* argv[],char* env[])
{
char* ptr = getenv("MYVAL");
if(ptr == NULL)
{
printf("NO MYVAL\n");
}
else
{
printf("%s\n",ptr);
}
return 0;
}