【Linux】进程

进程

进程:一个正在执行的程序。一个进程有一个 PCB(进程控制块)和一个内存指针(代码和数据),在 Linux 中的进程控制块称为 task_struct 。系统用 PCB 来描述进程的基本情况和活动过程,包含:进程ID、状态、优先级、寄存器内容、内存指针、资源分配信息、IO状态等。

bash 复制代码
#查看所有进程:
ps ajx

#查看指定进程(进程名一般就是运行的程序名):
ps ajx | grep 进程名

#用来显示进程的第一行,也就是表头信息,并显示processname进程的信息,&&可以理解为同时的意思
ps ajx | head -1 && ps axj | grep 进程名

# 获取进程 id
pid_t getpid(void)

#创建进程,若返回值为 0,则为子进程
fork()

# 终止进程:
kill -9 进程pid

进程状态

在操作系统中,进程状态分为:新建、就绪、运行、阻塞、终止。
新建 :进程刚被创建,在这个阶段,操作系统正在为进程分配资源和初始化PCB等信息。
就绪 :进程已经准备好运行,但还未获得CPU资源,在就绪队列中等待被调度。
运行 :进程正在执行指令。
阻塞 :进程正等待某种事件(I/O 操作)而无法继续执行,等待期间,进程不占用CPU资源。
终止:进程正常执行结束,或由操作系统/用户强制终止。

状态转换条件:
新建到就绪 :进程初始化完成,资源分配完成,进入就绪队列等待调度。
就绪到运行 :被调度程序选中。
运行到阻塞 :等待资源(如I/O请求)
阻塞到就绪 :资源可用(如I/O完成)
运行到就绪 :时间片用完或被更高优先级进程抢占。
运行到终止:进程正常执行结束,或由操作系统/用户强制终止

而在Linux中,进程有以下更具体的状态:

R:运行状态,并不一定在运行,也可能在运行队列中。

S:睡眠状态,进程在等待事件完成。

D:磁盘休眠状态,进程通常会等待IO的结束。

T:停止状态,可以通过发送 SIGSTOP 信号给进程来停止进程,这个被暂停的进程可以通过发送 SIGCONT 信号让其继续。

X:死亡状态,这个状态是一个返回状态,在任务列表中看不到。

Z:僵尸进程,已经运行完毕,但是要维持自己的退出信息,在自己的进程 task_struct 会记录自己的退出信息,未来让父进程来进行读取。

此外还有中孤儿进程,即父进程已经终止,但自身还在运行的进程。

进程优先级

进程优先级是指进程获取某种资源的先后顺序,优先级高的进程有优先执行的权利。可以使用命令 ps -l 查看系统进程:

进程创建

cpp 复制代码
#include <unistd.h>
pid_t fork();
返回值:子进程中返回0,父进程返回子进程id,出错返回-1

进程调用 fork 后,内核需要:

分配新的内存块和内核数据结构给子进程

将父进程部分数据结构内容拷贝至子进程

添加子进程到系统进程列表中

fork 返回,开始调度

cpp 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
    pid_t pid;
    printf("Before: pid is %d\n", getpid());
    if ((pid = fork()) == -1)
    {
        perror("fork()");
        exit(1);	//进程退出方法
    }

    if (pid == 0) {
        // 子进程逻辑
        printf("I am child, PID=%d\n", getpid());
    } else {
        // 父进程逻辑
        printf("I am parent, my child PID=%d\n", pid);
    }
    sleep(1);
    return 0;
}

运行结果:

cpp 复制代码
Before: pid is 665336
I am parent, my child PID=665337
I am child, PID=665337

进程等待

当子进程退出时,它的PCB不会立即被内核释放,而是保留部分信息,等待父进程完成后续内容(收尸),如果父进程不调用 wait,子进程就变成僵尸进程,僵尸进程会占用进程表项,大量僵尸进程就会导致系统无法创建新进程。

cpp 复制代码
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
返回值:成功返回被等待进程pid,失败返回-1
参数:输出型参数,获取子进程退出状态,不关心则可以设置为 NULL

pid_t waitpid(pid_t pid, int *status, int options);
返回值:成功返回被等待进程pid,失败返回-1
参数:pid 为等待哪个子进程,status获取子进程退出状态,options控制行为的标志位

wait 和 waitpid 作用:阻塞父进程,直到某个子进程结束;获取子进程的退出状态;通知内核彻底释放子进程资源,避免僵尸进程。

进程程序替换

进程程序替换 是指一个正在运行的进程 用另一个可执行程序的内容覆盖自己的地址空间,并从新程序的 main 函数开始执行。 这个过程不会创建新进程(PID不变)。

应用场景:终端输入 ls,fork 一个子进程,子进程通过 exec 替换成 /bin/ls 程序。或 父进程创建子进程,让子进程替换成目标服务程序。
exec函数:

这些函数调用出错则返回-1,成功则加载新的程序从启动代码开始执行,不会返回。

bash 复制代码
#include <unistd.h>`
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ...,char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
l------表示参数采用列表
v------表示参数用数组
p------有p则自动搜索环境变量PATH
e------表示自己维护环境变量

execl("/bin/ls", "ls", "-l", "/home", NULL);
第一个参数:可执行文件的完整路径;
第二个及后续参数:传递给新程序的 argv[0], argv[1], ...;
必须以 (char *)NULL 结尾(表示参数列表结束);

例如:

bash 复制代码
int main()
{
	char *const argv[] = {"ps", "-ef", NULL};
	char *const envp[] = {"PATH=/bin:/usr/bin", "TERM=console", NULL};
	execl("/bin/ps", "ps", "-ef", NULL);
	
	// 带p的,可以使用环境变量PATH,无需写全路径
	execlp("ps", "ps", "-ef", NULL);
	// 带e的,需要自己组装环境变量
	execle("ps", "ps", "-ef", NULL, envp);
	// 带v的
	execv("/bin/ps", argv);
	// 带p的,可以使用环境变量PATH,无需写全路径
	execvp("ps", argv);
	// 带e的,需要自己组装环境变量
	execve("/bin/ps", argv, envp);
	exit(0);
}
相关推荐
濊繵2 小时前
Linux网络--网络层协议 IP
服务器·网络·tcp/ip
Upper9992 小时前
简单记录:TCP数据包的抓取--3次握手、4次挥手
网络·网络协议·tcp/ip
java_logo2 小时前
宝塔 Linux 面板 Docker 容器化部署指南
linux·运维·docker·宝塔·docker部署宝塔·宝塔部署教程·docker部署baota
油丶酸萝卜别吃2 小时前
修改chrome配置,关闭跨域校验
前端·chrome
南烟斋..2 小时前
Linux进程管理完全指南:创建、终止、回收与替换
linux·算法
sunon_2 小时前
解决linux系统PDF中文乱码问题
linux·运维·pdf
BJ_bafangonline3 小时前
Xmanager怎么显示远程linux程序的图像?
linux·运维·服务器
ZeroNews内网穿透3 小时前
Dify AI 结合ZeroNews 实现公网快速访问
网络·人工智能·网络协议·tcp/ip·安全·web安全
云水木石3 小时前
Rust 语言开发的 Linux 桌面来了
linux·运维·开发语言·后端·rust