Linux 是一个典型的多任务操作系统,支持通过 多进程(Multiprocessing) 实现并发执行。每个进程拥有独立的地址空间和系统资源,通过进程间通信(IPC)进行协作。以下是 Linux 多进程的核心概念、使用方法和应用场景的详细解析。
进程(Process) 是程序的执行实例,包含代码、数据、内存空间、文件描述符、环境变量等资源。
每个进程在 Linux 内核中由 task_struct
结构体管理,并具有唯一的进程标识符(PID)。
父子关系:通过 fork()
创建的进程形成父子关系,父进程监控子进程状态。
特性 | 进程 | 线程 |
---|---|---|
资源隔离 | 独立内存空间,资源隔离 | 共享同一进程的内存和资源 |
创建开销 | 高(需复制父进程资源) | 低(共享进程资源) |
通信方式 | 管道、共享内存、信号等 IPC | 全局变量、互斥锁等 |
容错性 | 一个进程崩溃不影响其他进程 | 一个线程崩溃可能导致整个进程终止 |
fork()
系统调用:复制当前进程,生成子进程。
返回值:父进程返回子进程 PID,子进程返回 0。
写时复制(Copy-On-Write):Linux 优化机制,父子进程共享内存,直到修改时才复制。
#include
pid_t pid = fork();
if (pid == 0) {
// 子进程代码
} else if (pid > 0) {
// 父进程代码
} else {
// fork 失败
}
exec()
系列函数:替换当前进程的代码段,加载新程序。
execl("/bin/ls", "ls", "-l", NULL); // 执行 ls -l
正常终止:通过 exit()
或 return
结束进程。
异常终止:收到信号(如 SIGKILL
、SIGSEGV
)或被其他进程终止。
僵尸进程(Zombie):子进程终止后,父进程未调用 wait()
回收资源,导致残留进程信息。
孤儿进程(Orphan):父进程先终止,子进程被 init
进程(PID=1)接管。
wait()
/ waitpid()
:父进程阻塞等待子进程终止,并回收资源。
int status;
pid_t child_pid = wait(&status); // 等待任意子进程
pid_t child_pid = waitpid(pid, &status, WNOHANG); // 等待指定子进程,非阻塞模式
匿名管道:单向通信,用于父子进程。
int pipe_fd[2];
pipe(pipe_fd); // pipe_fd[0]读端,pipe_fd[1]写端
命名管道(FIFO):通过文件系统路径标识,支持无关进程通信。
mkfifo /tmp/myfifo
多个进程映射同一块物理内存,高效但需同步机制(如信号量)。
int shm_id = shmget(IPC_PRIVATE, size, IPC_CREAT | 0666);
char *shm_ptr = shmat(shm_id, NULL, 0);
内核维护的链表结构,支持有类型消息传递。
int msgq_id = msgget(IPC_PRIVATE, IPC_CREAT | 0666);
msgsnd(msgq_id, &msg, sizeof(msg), 0);
msgrcv(msgq_id, &msg, sizeof(msg), msg_type, 0);
用于进程间同步,控制对共享资源的访问。
sem_t sem;
sem_init(&sem, 1, 1); // 初始值1(二进制信号量)
sem_wait(&sem); // P操作
sem_post(&sem); // V操作
支持跨网络通信,也可用于本地进程间通信(AF_UNIX)。
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
进程组(Process Group):一组相关进程的集合,共享同一 PGID。
会话(Session):一个或多个进程组的集合,通常由 Shell 创建。
后台运行的独立进程,脱离终端控制。
创建步骤:
调用 fork()
创建子进程,父进程退出。
调用 setsid()
创建新会话。
关闭文件描述符,重定向标准 I/O。
并行计算:利用多核 CPU 加速任务(如数据处理、科学计算)。
服务端程序:Web 服务器(如 Apache)通过多进程处理并发请求。
任务隔离:将不稳定模块(如第三方插件)运行在独立进程,避免主程序崩溃。
批处理系统:同时执行多个独立任务(如编译、文件转换)。
#include
#include
#include
int main() {
int pipe_fd[2];
char buf[20];
pipe(pipe_fd);
if (fork() == 0) { // 子进程
close(pipe_fd[0]); // 关闭读端
write(pipe_fd[1], "Hello Parent!", 13);
close(pipe_fd[1]);
} else { // 父进程
close(pipe_fd[1]); // 关闭写端
read(pipe_fd[0], buf, sizeof(buf));
printf("Received: %s\n", buf);
close(pipe_fd[0]);
wait(NULL);
}
return 0;
}
特性 | 多进程优势 | 多进程劣势 |
---|---|---|
资源隔离 | 安全性高,一个进程崩溃不影响其他进程 | 内存占用高 |
通信复杂度 | 需显式 IPC 机制 | 编程复杂度高于多线程 |
扩展性 | 适合分布式系统或需要强隔离的场景 | 进程间切换开销大 |
选择建议:
需要强隔离性、稳定性时选择多进程。
需要轻量级并发、数据共享频繁时选择多线程。
掌握 Linux 多进程技术是系统级开发的必备技能,合理使用可显著提升程序性能和可靠性。