1. Linux进程控制基础概念
在Linux系统中,进程控制是系统管理的核心能力之一。每个运行中的程序都会创建一个或多个进程,操作系统通过进程控制块(PCB)来管理这些进程的生命周期。理解进程控制,首先要掌握几个关键概念:
-
进程标识符(PID):每个进程都有唯一的数字标识,范围从1到32768。PID 1通常是init进程(现代系统可能是systemd),它是所有其他进程的父进程。
-
进程状态:Linux进程主要包含以下几种状态:
- 运行态(R)
- 可中断睡眠(S)
- 不可中断睡眠(D)
- 停止态(T)
- 僵尸态(Z)
-
进程关系:进程之间存在父子关系,使用
pstree命令可以直观查看这种层级结构。父进程终止时,子进程会成为孤儿进程,被init进程接管。
注意:在实际操作中,使用
ps aux命令查看进程状态时,STAT列显示的就是上述状态码。理解这些状态对进程管理至关重要。
2. 进程创建与控制
2.1 fork()系统调用
进程创建主要通过fork()系统调用实现。这个调用会创建一个与父进程几乎完全相同的子进程,包括代码段、数据段、堆栈等。关键区别在于:
- 子进程有自己的PID
- 子进程的PPID(父进程ID)是调用fork()的进程ID
- 子进程继承父进程的文件描述符表
c复制#include <unistd.h>
#include <stdio.h>
int main() {
pid_t pid = fork();
if (pid == 0) {
printf("这是子进程,PID=%d\n", getpid());
} else if (pid > 0) {
printf("这是父进程,子进程PID=%d\n", pid);
} else {
perror("fork失败");
return 1;
}
return 0;
}
2.2 exec系列函数
exec系列函数用于替换当前进程的映像,加载并执行新程序。常见的变体包括:
- execl():参数列表形式
- execv():参数数组形式
- execle():带环境变量
- execvp():在PATH中搜索可执行文件
c复制#include <unistd.h>
int main() {
char *args[] = {"ls", "-l", NULL};
execvp("ls", args);
perror("execvp失败");
return 1;
}
3. 进程间通信(IPC)
Linux提供了多种进程间通信机制,各有适用场景:
3.1 管道(Pipe)
管道是最简单的IPC方式,特点包括:
- 单向通信
- 只能用于有亲缘关系的进程
- 容量有限(通常4KB)
bash复制# 命令行中使用管道
ps aux | grep ssh
3.2 共享内存
共享内存是最高效的IPC方式,允许多个进程访问同一块内存区域。使用步骤:
- 创建共享内存段(shmget)
- 附加到进程地址空间(shmat)
- 使用完成后分离(shmdt)
- 删除共享内存段(shmctl)
3.3 消息队列
消息队列允许进程以消息形式交换数据,特点包括:
- 消息类型标识
- 可以非先进先出顺序读取
- 内核持久化(直到显式删除)
4. 进程监控与管理工具
4.1 常用命令行工具
-
ps:查看进程状态bash复制ps aux | less # 查看所有用户的所有进程 ps -ef --forest # 显示进程树 -
top/htop:实时监控进程bash复制top -u username # 监控特定用户进程 -
kill:发送信号给进程bash复制kill -9 PID # 强制终止进程 kill -l # 列出所有信号
4.2 系统调用监控
使用strace可以跟踪系统调用和信号:
bash复制strace -f -o output.txt command # 跟踪命令及其子进程
5. 进程优先级与调度
Linux采用完全公平调度器(CFS)来管理进程CPU时间分配。关键概念:
-
nice值:范围-20到19,值越小优先级越高
bash复制nice -n 10 command # 以较低优先级运行命令 renice 5 -p PID # 修改运行中进程的优先级 -
实时优先级:SCHED_FIFO和SCHED_RR策略使用1-99的优先级
注意:普通用户只能降低优先级(增加nice值),只有root可以提升优先级。
6. 守护进程创建
守护进程是在后台运行的系统服务进程,创建步骤包括:
- 调用fork()创建子进程
- 在子进程中调用setsid()创建新会话
- 再次fork()确保不是会话首进程
- 更改工作目录到根目录
- 重设文件创建掩码
- 关闭继承的文件描述符
- 重定向标准I/O到/dev/null
c复制#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
void daemonize() {
pid_t pid = fork();
if (pid < 0) exit(EXIT_FAILURE);
if (pid > 0) exit(EXIT_SUCCESS); // 父进程退出
if (setsid() < 0) exit(EXIT_FAILURE); // 创建新会话
pid = fork();
if (pid < 0) exit(EXIT_FAILURE);
if (pid > 0) exit(EXIT_SUCCESS); // 再次fork
umask(0); // 重设文件掩码
chdir("/"); // 更改工作目录
// 关闭标准文件描述符
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
// 重定向到/dev/null
open("/dev/null", O_RDONLY);
open("/dev/null", O_RDWR);
open("/dev/null", O_RDWR);
}
7. 进程组与会话
Linux使用进程组和会话管理相关进程:
- 进程组:共享同一PGID的一组进程,通常是一个shell命令及其子进程
- 会话:一个或多个进程组的集合,通常对应一个登录会话
关键操作:
c复制setpgid(pid_t pid, pid_t pgid); // 设置进程组
setsid(); // 创建新会话
tcsetpgrp(int fd, pid_t pgrp); // 设置控制终端的前台进程组
8. 信号处理
信号是进程间通信的异步机制,常见信号包括:
- SIGTERM(15):优雅终止
- SIGKILL(9):强制终止
- SIGINT(2):终端中断(Ctrl+C)
- SIGSTOP(19):暂停进程
- SIGCONT(18):继续执行暂停的进程
信号处理示例:
c复制#include <signal.h>
#include <stdio.h>
void handler(int sig) {
printf("收到信号 %d\n", sig);
}
int main() {
signal(SIGINT, handler); // 捕获Ctrl+C
while(1) pause(); // 等待信号
return 0;
}
9. 进程资源限制
使用getrlimit和setrlimit可以查询和设置进程资源限制:
c复制#include <sys/resource.h>
struct rlimit {
rlim_t rlim_cur; // 软限制
rlim_t rlim_max; // 硬限制
};
int main() {
struct rlimit limit;
// 获取文件描述符限制
getrlimit(RLIMIT_NOFILE, &limit);
printf("当前文件描述符限制: %ld\n", limit.rlim_cur);
// 设置核心转储大小限制
limit.rlim_cur = 1024 * 1024; // 1MB
limit.rlim_max = 1024 * 1024;
setrlimit(RLIMIT_CORE, &limit);
return 0;
}
命令行中可以使用ulimit命令查看和设置限制:
bash复制ulimit -a # 显示所有限制
ulimit -n 1024 # 设置文件描述符限制为1024
10. 实战案例:构建简易进程管理器
下面是一个用C语言实现的简易进程管理器,包含以下功能:
- 启动新进程
- 列出所有进程
- 终止指定进程
- 监控进程状态
c复制#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#define MAX_CMD_LEN 256
void start_process() {
char cmd[MAX_CMD_LEN];
printf("输入要执行的命令: ");
fgets(cmd, MAX_CMD_LEN, stdin);
pid_t pid = fork();
if (pid == 0) {
// 子进程
system(cmd);
exit(0);
} else if (pid > 0) {
printf("启动进程 PID: %d\n", pid);
} else {
perror("fork失败");
}
}
void list_processes() {
system("ps aux");
}
void kill_process() {
pid_t pid;
printf("输入要终止的PID: ");
scanf("%d", &pid);
getchar(); // 消耗换行符
if (kill(pid, SIGTERM) == 0) {
printf("已发送终止信号给进程 %d\n", pid);
} else {
perror("终止进程失败");
}
}
int main() {
int choice;
while (1) {
printf("\n简易进程管理器\n");
printf("1. 启动新进程\n");
printf("2. 列出所有进程\n");
printf("3. 终止进程\n");
printf("4. 退出\n");
printf("选择操作: ");
scanf("%d", &choice);
getchar(); // 消耗换行符
switch (choice) {
case 1:
start_process();
break;
case 2:
list_processes();
break;
case 3:
kill_process();
break;
case 4:
exit(0);
default:
printf("无效选择\n");
}
}
return 0;
}
编译并运行:
bash复制gcc process_manager.c -o process_manager
./process_manager
这个简易管理器展示了Linux进程控制的核心功能,包括进程创建、列表查看和终止操作。在实际系统编程中,可能需要更完善的错误处理和更丰富的功能。
