插件窝 干货文章 Linux进程管理之如何创建和销毁进程

Linux进程管理之如何创建和销毁进程

进程 include const char 56    来源:    2025-05-14

Linux进程管理:创建与销毁进程详解

进程创建

在Linux系统中,主要有以下几种创建进程的方式:

1. fork()系统调用

#include <unistd.h>

pid_t fork(void);
  • 创建一个与父进程几乎完全相同的子进程
  • 子进程获得父进程数据空间、堆和栈的副本
  • 返回值:
    • 父进程中返回子进程的PID
    • 子进程中返回0
    • 出错时返回-1

2. vfork()系统调用

#include <unistd.h>

pid_t vfork(void);
  • 创建子进程但不复制父进程的页表
  • 子进程共享父进程的内存空间直到调用exec()或exit()
  • 通常用于紧接着exec()的情况

3. exec()系列函数

#include <unistd.h>

int execl(const char *path, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execle(const char *path, const char *arg, ..., char *const envp[]);
int execve(const char *path, char *const argv[], char *const envp[]);
int execlp(const char *file, const char *arg, ...);
int execvp(const char *file, char *const argv[]);
  • 用新程序替换当前进程的代码段、数据段、堆和栈
  • 不创建新进程,只是替换当前进程映像

4. system()函数

#include <stdlib.h>

int system(const char *command);
  • 创建一个shell来执行指定的命令
  • 内部实现通常使用fork()、exec()和waitpid()

5. popen()函数

#include <stdio.h>

FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);
  • 创建一个管道,fork一个子进程,然后执行shell命令
  • 可以读取命令输出或向命令输入数据

进程销毁

1. 正常终止

  • 从main函数返回
  • 调用exit()函数
  • 调用_exit()或_Exit()函数
#include <stdlib.h>

void exit(int status);
void _Exit(int status);

#include <unistd.h>

void _exit(int status);

2. 异常终止

  • 收到终止信号
  • 调用abort()函数
#include <stdlib.h>

void abort(void);

3. 进程等待

父进程通常需要等待子进程终止:

#include <sys/wait.h>

pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
  • wait()阻塞直到任一子进程终止
  • waitpid()可以指定等待特定子进程,并提供非阻塞选项

4. 僵尸进程处理

  • 子进程终止但父进程未调用wait(),进程变为僵尸状态
  • 解决方法:
    • 父进程调用wait()或waitpid()
    • 忽略SIGCHLD信号:signal(SIGCHLD, SIG_IGN);
    • 使用两次fork()技术

实际示例

创建进程示例

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main() {
    pid_t pid;

    pid = fork();

    if (pid < 0) {
        fprintf(stderr, "Fork failed");
        return 1;
    } else if (pid == 0) {
        // 子进程
        printf("Child process (PID: %d)\n", getpid());
        execlp("/bin/ls", "ls", NULL);
    } else {
        // 父进程
        printf("Parent process (PID: %d), Child PID: %d\n", getpid(), pid);
        wait(NULL);
        printf("Child complete\n");
    }

    return 0;
}

销毁进程示例

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    pid_t pid = fork();

    if (pid == 0) {
        // 子进程
        printf("Child process running...\n");
        sleep(2);
        printf("Child process exiting\n");
        exit(0);  // 子进程正常退出
    } else if (pid > 0) {
        // 父进程
        printf("Parent waiting for child...\n");
        wait(NULL);  // 等待子进程结束
        printf("Parent detected child exit\n");
    } else {
        perror("fork failed");
        exit(1);
    }

    return 0;
}

最佳实践

  1. 总是检查fork()的返回值
  2. 子进程退出时使用exit()而不是return
  3. 父进程应该等待子进程结束以避免僵尸进程
  4. 考虑使用进程池模式管理大量子进程
  5. 对于需要频繁创建销毁的进程,考虑线程替代方案

通过合理使用这些进程创建和销毁机制,可以构建高效、稳定的Linux应用程序。