系统进程概念
一、进程的概念和结构
1.概念:
- 程序:程序是存放在磁盘文件中的可执行文件
- 进程:
- 程序的执行实例被称为进程(process)
- 进程具有独立的权限与职责。如果系统中某个进程崩溃,他不会影响到其余进程。
- 每个进程运行在各自的虚拟地址空间中,进程之间可以通过由内核控制的机制相互通信。
- 进程ID
- 每个linux进程都一定有一个唯一的数字标识符,称为进程ID(process ID),进程ID总是一个非负整数。
linux内核中的文件:文件描述符表->文件表项->i节点->外部硬盘
进程在内核当中的结构:
/usr/src/linux-headers/include/linux/sched.h
task_struct
二、进程的启动,终止,查看,状态,调度
1.C语言的启动
-
内核启动特殊例程
-
启动例程
- 在进程的main函数执行之前内核会启动
- 该例程放置在/lib/libc.so.***中
- 编译器在编译时会将启动例程编译进可执行文件中
-
启动例程作用
- 搜集命令行的参数传递给main函数中的atgc和argv
- 搜集环境信息构建环境表并传递给main函数 (带参main的第三个形参,一般不用)
- 向内核登记进程的终止函数
2.C语言的终止
-
正常终止
- 从main函数返回
- 调用exit (标准c库函数)
- 调用_exit或_Exit (系统调用)
- 最后一个线程从其启动例程返回
- 最后一个线程调用pthread_exit
-
异常终止
- 调用abort
- 接受到一个信号并终止(比如段错误信号)
- 最后一个线程对取消请求做处理响应
-
进程返回
- 通常程序运行成功返回0,否则返回非0
- 在shell中可以查看进程返回值(echo $?)
3.atexit函数
#include <stdlib.h>
int atexit(void (*function)(void));
返回:若成功则为0,若出错则为-1
功能:向内核登记终止函数
- 每个启动的进程都默认登机了一个标准的终止函数
- 终止函数在进程终止时释放进程所占用的一些资源
- 登记的多个终止函数执行顺序是以栈的方式执行,先登记的后执行
示例:
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
//定义进程的终止函数
void term_fun1(void)
{
printf("first term func\n");
}
void term_fun2(void)
{
printf("second term func\n");
}
void term_fun3(void)
{
printf("third term func\n");
}
int main(int argc, char argv[])
{
if(argc<3)
{fprintf(stderr,"usage:%s file [exit|_exit|return]\n",argv[0]);exit(1);}
//向内核登记终止函数,以栈方式存储FILO,在函数结束(比如运行return,exit函数)的时候会调度运行
atexit(term_fun1);
atexit(term_fun2);
atexit(term_fun3);
FILE* fp = fopen(argv[1],"w");
fprintf(fp,"hello"); //全缓存,当缓存全满才一次性写入文件里边
if(! strcmp(argv[2],"exit") )exit(0);
else if(! strcmp(argv[2],"_exit") )_exit(0);//特别的这个不会运行atexit,也不会清除缓存
else if(! strcmp(argv[2],"return") )return 0;
else fprintf(stderr,\
"usage:%s file [exit|_exit|return]\n",argv[0]);
}
4.进程终止方式区别
-|return|exit()|_exit()/_Exit()|
是否刷新标准I/O内存|是|是|否
是否自动调用终止函数|是|是|否
- _exit()/_Exit()是直接和内核连接的,exit()源码中是使用_Exit()结束的
5.查看系统中的进程
- ps指令:
- 通常可以看到:进程的ID、进程状态和进程的Command
$ps -ef | more #查看后台信息
$ps -aux | more #查看进程占CPU、内存多少空间
ps输出信息:
USER|进程属主
PID|进程的ID
PPID|父进程
%CPU|进程占用的CPU百分比
%MEM|占用内存的百分比
NI|进程的NICE值,数值大,表示较少占用CPU
VSZ|进程虚拟大小
RSS|驻留中页的数量
TTY|终端ID
WCHAN|正在等待的进程资源
START|启动进程的时间
STAT|进程的状态
TIME|进程消耗CPU的时间
COMMAND|命令的名称和参数
6.进程状态 STAT
- 运行状态
- 系统当前进程
- 就绪状态进程
- ps命令的STAT列 为值R (Run)
- 等待状态
- 等待事件发生
- 等待系统资源
- 可中断和不可中断等待态
- ps命令的STAT列 为值S (Sleep)
- 停止状态
- 阻塞,挂起
- ps命令的STAT列 为值T
- 僵尸状态
- 进程终止或结束
- 在进程表项中仍有记录
- ps命令的STAT列 为值Z (Zombi)
7.进程调度
- 第一步:处理内核中的工作
- 第二步:处理当前进程
- 第三步:选择进程
- 实时进程
- 普通进程
- 第四步:进程交换
task_struct中的调度信息:
- 策略
- 轮流策略
- 先进先出策略
- 优先权
- jiffies变量
- 实时优先权
- 实时进程之间
- 计数器
8.进程状态变化关系
三、进程编程
1.进程标识
/*
#include <unistd.h>
#include <sys/types.h>
pid_t getpid(void); //获得当前进程ID
uid_t getuid(void); //获得当前进程的实际用户ID
uid_t geteuid(void); //获得当前进程的有效用户ID
gid_t getgid(void); //获得当前进程的用户组ID
pid_t getppid(void); //获得当前进程的父进程ID
pid_t getpgrp(void); //获得当前进程所在的进程组ID
pid_t getpgid(pid_t pid); //获得进程ID为pid的进程所在的进程组ID
*/
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
printf("pid:%d\n",getpid());
printf("ppid:%d\n",getppid());
printf("uid:%d\n",getuid());
printf("euid:%d\n",geteuid());
printf("user gid:%d\n",getgid()); //用户组id
printf("gid:%d\n",getpgrp()); //进程组id
printf("pgid:%d\n",getpgid(getpid()));
printf("ppgid:%d\n",getpgid(getppid()));
return 0;
}
将实际用户的权限提升为超级用户root,他的euid为0
$sudo chown root.root process_id #修改用户权限
$sudo chmod u+s process_id #s为粘着位,作用为修改当前用户的有效用户