Linux 多进程详解

Linux 多进程详解

Linux 是一个典型的多任务操作系统,支持通过 多进程(Multiprocessing) 实现并发执行。每个进程拥有独立的地址空间和系统资源,通过进程间通信(IPC)进行协作。以下是 Linux 多进程的核心概念、使用方法和应用场景的详细解析。


一、进程的基本概念 ⚙️

1. 什么是进程?
  • 进程(Process) 是程序的执行实例,包含代码、数据、内存空间、文件描述符、环境变量等资源。

  • 每个进程在 Linux 内核中由 task_struct 结构体管理,并具有唯一的进程标识符(PID)。

  • 父子关系:通过 fork() 创建的进程形成父子关系,父进程监控子进程状态。

2. 进程与线程的区别
特性 进程 线程
资源隔离 独立内存空间,资源隔离 共享同一进程的内存和资源
创建开销 高(需复制父进程资源) 低(共享进程资源)
通信方式 管道、共享内存、信号等 IPC 全局变量、互斥锁等
容错性 一个进程崩溃不影响其他进程 一个线程崩溃可能导致整个进程终止

二、进程的生命周期

1. 进程的创建
  • 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
    
2. 进程的终止
  • 正常终止:通过 exit()return 结束进程。

  • 异常终止:收到信号(如 SIGKILLSIGSEGV)或被其他进程终止。

  • 僵尸进程(Zombie):子进程终止后,父进程未调用 wait() 回收资源,导致残留进程信息。

  • 孤儿进程(Orphan):父进程先终止,子进程被 init 进程(PID=1)接管。

3. 进程的等待
  • wait() / waitpid():父进程阻塞等待子进程终止,并回收资源。

    int status;
    pid_t child_pid = wait(&status); // 等待任意子进程
    pid_t child_pid = waitpid(pid, &status, WNOHANG); // 等待指定子进程,非阻塞模式
    

三、进程间通信(IPC)

1. 管道(Pipe)
  • 匿名管道:单向通信,用于父子进程。

    int pipe_fd[2];
    pipe(pipe_fd); // pipe_fd[0]读端,pipe_fd[1]写端
    
  • 命名管道(FIFO):通过文件系统路径标识,支持无关进程通信。

    mkfifo /tmp/myfifo
    
2. 共享内存(Shared Memory)
  • 多个进程映射同一块物理内存,高效但需同步机制(如信号量)。

    int shm_id = shmget(IPC_PRIVATE, size, IPC_CREAT | 0666);
    char *shm_ptr = shmat(shm_id, NULL, 0);
    
3. 消息队列(Message Queue)
  • 内核维护的链表结构,支持有类型消息传递。

    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);
    
4. 信号量(Semaphore)
  • 用于进程间同步,控制对共享资源的访问。

    sem_t sem;
    sem_init(&sem, 1, 1); // 初始值1(二进制信号量)
    sem_wait(&sem);   // P操作
    sem_post(&sem);   // V操作
    
5. 套接字(Socket)
  • 支持跨网络通信,也可用于本地进程间通信(AF_UNIX)。

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    

四、进程管理

1. 进程组与会话 ‍‍
  • 进程组(Process Group):一组相关进程的集合,共享同一 PGID。

  • 会话(Session):一个或多个进程组的集合,通常由 Shell 创建。

2. 守护进程(Daemon) ‍♂️
  • 后台运行的独立进程,脱离终端控制。

  • 创建步骤:

    1. 调用 fork() 创建子进程,父进程退出。

    2. 调用 setsid() 创建新会话。

    3. 关闭文件描述符,重定向标准 I/O。


五、多进程的典型应用场景

  1. 并行计算:利用多核 CPU 加速任务(如数据处理、科学计算)。

  2. 服务端程序:Web 服务器(如 Apache)通过多进程处理并发请求。

  3. 任务隔离:将不稳定模块(如第三方插件)运行在独立进程,避免主程序崩溃。

  4. 批处理系统:同时执行多个独立任务(如编译、文件转换)。


六、多进程编程示例

父子进程通过管道通信
#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 多进程技术是系统级开发的必备技能,合理使用可显著提升程序性能和可靠性。

你可能感兴趣的:(linux,运维,服务器)