【DAY24】Linux软件编程:进程原理、命令及编程实现总结
本文介绍了进程和线程的基本概念及相关操作。进程是程序的动态执行过程,包含创建、调度和消亡三个阶段。文章详细讲解了进程管理命令(如top、ps、kill等)、进程状态(运行态、就绪态等)、进程空间分布(虚拟地址与物理地址映射)以及进程调度算法。同时介绍了进程创建函数fork()和相关系统调用(如getpid、wait等)。线程部分阐述了其轻量级特性,对比了进程与线程的区别(空间独立性、资源分配等),
一、进程
1.概念
- 进程是程序动态运行的过程,包括创建、调度、消亡的整个过程
- 程序:存放在硬盘中的一段数据集合
2.进程的相关命令
1.top
根据CPU占用率查看所有进程任务信息
PID:进程ID号(每个进程唯一), 该值>0;
PPID:父进程ID号
2.ps-ef
查看当前系统下所有的进程任务信息
ps -ef | grep 进程名
3.ps -aux
查看进程信息(进程状态)
ps -aux | grep 进程名
4.kill
杀死一个进程任务
kill -9 进程ID
killall -9 进程名
5.&
在后台执行任务
./a.out &
6. ps
查看一个终端所有的前后台任务
7. jobs
查看所有的后台任务及其编号
8. fg 编号
将后台任务放到前台执行
9.nice
使用指定优先级(-20,20)执行进程任务
nice -n 优先级 任务
10.renice
重新设置一个正在运行的进程的优先级
renice -n 优先级 进程PID
3.进程的创建
1.虚拟地址
MMU映射后的可以访问的内存空间
2.物理地址
硬件实际的RAM空间地址,用户一般不允许直接访问物理地址,要通过MMU映射
为虚拟地址再进行访问
3.虚拟地址空间分布
每个进程执行,操作系统会为进程分配0-4G虚拟内存空间
- 内核:用户无法访问
- 栈区(.stack):默认8M,未经初始化值为随机值,超过变量作用域回收变量空间,
增长方向自高向低- 堆区:(.heap):剩余的空间为堆区,可以由程序员手动申请释放,增长方向自低向高增长
- 数据区
- 存放字符串常量(.rodata)
- 已初始化静态变量、全局变量(.data):在编译时分配空间,程序运行时加载存空间中
- 未初始化静态变量、全局变量(.bss):在进程启动后由进程默认初始化为0值
- 文本区(.text):存放代码和相关指令
4.多个进程的空间
进程空间是独立的
- 多进程进程共用同一虚拟地址空间,但物理是独立的
- 进程1执行时MMU将进程1的物理地址空间映射到虚拟地址空间中
- 进程2执行时MMU将进程2的物理地址空间映射到虚拟地址空间中

4.进程调度
- 先来先执行,后来后执行
- 短作业优先执行
- 高优先级先执行
- 时间片轮转调度算法
- CPU在任务中运行的一段时间称为时间片(5-10ms)
- 宏观并行,微观串行
- 多级队列反馈调度算法
- 负载均衡调度算法
- 抢占式调度算法

5.进程状态
1.运行态(R)
任务正在被CPU执行
2.就绪态(R)
任务正在处于就绪队列中,但未被CPU找到
3.可换醒等待态(S)
任务等待某个资源被CPU挂起,等待过程中可以被唤醒
4.不可唤醒等待态(D)
任务等待某个资源被CPU挂起,等待过程不能被打断
5.停止态(T)
用户将某个任务暂停
6.僵尸态(Z)
进程执行结束, 空间未被回收
7.结束态(X)
进程执行结束, 空间被回收
6.进程相关函数接口
1.fork
pid_t fork(void);
功能:
- 创建一个子进程空间
参数:
- 缺省
返回值:
- 成功父进程返回子进程的PID
- 子进程返回0
- 失败返回-1
子进程会拷贝父进程的文本段(代码)、数据段(静态变量、全局变量、字符串常
量)、堆区(malloc)、栈区(局部变量)、缓存区
2.getpid
pid_t getpid(void);
功能:
获得调用进程的PID
3.getppid
pid_t getppid(void);
功能:
获得调用进程的父进程PID
//为一个进程创建2个子进程,子进程中打印自己的PID和父进程的PID,父进程中打印自己的PID和2个子进程的PID
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main(void)
{
pid_t pid1;
pid_t pid2;
pid1 = fork();
if(-1 == pid1)
{
perror("fail to fork");
return -1;
}
if(0 == pid1)
{
printf("I am child1, PID:%d, PPID:%d\n", getpid(), getppid());
}
else if(pid1 > 0)
{
pid2 = fork();
if(0 == pid2)
{
printf("I am child2, PID:%d, PPID:%d\n", getpid(), getppid());
}
else if(pid2 > 0)
{
printf("I am parrent1, PID:%d, child1.pid:%d, chile2.pid:%d\n", getpid(), pid1, pid2);
}
}
while (1)
{
}
return 0;
}
4.exit
void exit (int status)
功能:
让进程结束 (在主函数中调用与return效果相同)
在主函数中调用exit和return 效果相同
5._exit
void _exit (int status)
功能:
直接让进程结束
exit:刷新缓存区, 执行一系列进程退出注册的操作,最后让进程结束
_exit: 不会刷新缓存区,直接让进程结束
6.wait
pid_t wait(int *wstatus)
功能:
回收子进程空间
具有阻塞功能, 子进程没结束, 父进程等待子进程结束后,回收子进程空间
参数:
wstatus:存放于进程结束状态空间的首地址
返回值:
成功返回回收到的子进程的PID
失败返回 -1;
WIFEXITED(wstatus):判断子进程是否正常退出
WEXITSTATUS(wstatus):获得子进程结束时的值
WIFSIGNALED(wstatus):判断子进程是否被信号杀死
WTERMSIG(wstatus):获得杀死子进程信号的值
WCOREDUMP(wstatus):判断子进程是否段错误退出
WIFSTOPPED(wstatus):判断子进程是否被停止
WSTOPSIG(wstatus):获得停止子进程的编号
WIFCONTINUED(wstatus):判断进程是否继续执行
7.waitpid
pid_t waitpid(pid_t pid, int * wstatus, int optinons);
功能:
- 回收指定的子进程空间
参数:
- pid: 回收子进程的id号, -1表示任意子进程
- wstatus:存放子进程结束状态空间的首地址
- options:
0 阻塞回收
WNOHANG 非阻塞回收
返回值:
- 成功返回回收到的子进程的PID
- 失败返回-1
- 若是WNOHANG设置,没有子进程结束,返回0;
wait(NULL)==waitpid(-1,NULL,0)
7.进程的消亡
1)僵尸态
进程代码执行结束,但是空间没有被回收
2)避免僵尸态的方法
- 让父进程先结束, 子进程成为孤儿进程,孤儿进程会被init进程收养,子进程结束后,init回收子进程空间,避免产生僵尸进程
- 子进程结束,父进程回收子进程空间,避免产生僵尸进程
8.exec函数
int execl(const char *path, const char *arg, .../* (char *) NULL */);
int execlp(const char *file, const char *arg, .../* (char *) NULL */);
int execle(const char *path, const char *arg, .../*, (char *) NULL, char
* const envp[] */);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
功能:
利用进程空间执行另外的一段代码
l:参数以列表形式传递
v:参数以指针数组形式传递
p:在环境变量PATH对应的目录下找file
e:更新进程的环境变量
二、线程
1.概念
线程是轻量级的进程
2.进程和线程的区别
- 进程的空间是独立的
- 线程空间位于进程空间内部,独享栈区(每个线程栈区独立), 共享文本区、数据区、堆区、(一个进程中的多个线程共用上述区域)
- 进程是操作系统资源分配的最小单元
- 线程是cpu任务调度的最小单元
3.线程的创建
每个线程会创建一个 属于该线程的独立的栈空间(默认8M),文本区,数据区、堆区使用进程中的区域

4.线程的调度
- 等同于进程调度
- 宏观并行,微观串行
5.线程的消亡
- 等同于进程的消亡,线程消亡需要回收栈空间
6.多进程和多线程的优缺点
1.进程
- 每个进程空间独立,安全性好,一个进程异常崩溃不会影响其余进程
- 多余进程调度,效率低。切换进程任务时需要映射不同的物理地址,增大系统开销
- 多进程通性不方便,因为空间独立,没有共享空间
- 进程考虑资源竞争问题,因为没有共享空间
2.线程
- 线程位于进程空间内部, 线程异常崩溃会导致进程崩溃,进程中其余线程均结束
- 多线程调度效率高(在同一进程内部切换不同任务)
- 多线程调度非常方便,多线程数据区、堆区共享
- 通过锁的机制防止资源竞争
7. 线程相关函数接口:
1.pthread_create
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
功能:
- 创建一个线程任务
参数:
- thread:存放线程ID空间首地址
- attr:线程的属性,使用默认属性传NULL
- start_routine:线程函数入口
- arg:线程函数的参数
返回值:
成功返回0
失败返回非0
更多推荐
所有评论(0)