欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 幼教 > linux进程

linux进程

2025/9/22 4:48:46 来源:https://blog.csdn.net/2503_90266635/article/details/145763413  浏览:    关键词:linux进程

1. 进程创建与管理

在C语言中,进程的创建和管理是通过几个关键系统调用完成的。最常见的进程管理函数有 fork()execvp(),以及 wait()。我们来逐一分析它们。

fork() — 进程的复制

fork() 是用来创建新进程的系统调用。它会复制当前的进程(父进程),创建一个几乎完全相同的子进程。子进程从 fork() 调用之后继续执行,但有一个返回值区分父子进程:

  • 父进程返回子进程的PID(进程ID)。
  • 子进程返回0。

使用 fork() 时,父进程和子进程会在内存中各自运行,互不干扰。

execvp() — 执行新程序

execvp() 用于在当前进程的空间中加载并执行一个新程序。与 fork() 创建的新进程不同,execvp() 会替换当前进程的内存空间,加载一个新的程序执行。因此,execvp() 之后的代码将不再执行当前程序,而是执行新的程序。

例如,以下代码:

char *arg[] = {"ls", "-l", "/", NULL};
execvp(arg[0], arg);

执行了 ls -l / 命令,execvp() 会将当前进程替换成 ls 命令并执行。


2. 进程的退出

进程退出是操作系统中非常重要的一个环节。进程的退出有两种主要方式:正常退出和异常退出。

正常退出
  • exit():此函数用于正常退出进程,并可以传递一个退出状态值。这些退出状态值通常用于通知父进程该子进程的退出情况。

    void exit(int status);
    
  • _exit():这个函数和 exit() 类似,但不执行标准I/O缓冲区的清理工作,因此速度较快。通常在 fork() 后的子进程中使用 _exit() 来直接退出。

  • 进程正常退出有三种常见方式:

    1. 从 main() 函数返回。
    2. 使用 exit()
    3. 使用 _exit()
异常退出

异常退出指进程由于某些错误或信号终止,例如:

  • 被某个信号终止(如 kill 或 abort)。
  • 发生未捕获的异常。

其中 abort() 函数会生成一个信号,通常会导致程序异常退出。


3. wait()的使用

在多进程的程序中,父进程可能需要等待子进程的执行结果,或者等待子进程结束以清理资源。wait() 函数就可以实现这一功能。

wait() 函数

wait() 函数用于阻塞父进程,直到一个子进程结束。它还允许父进程获取子进程的退出状态。

pid_t wait(int *wstatus);
  • wstatus:指向一个整数变量,用于存储子进程的退出状态。如果 wstatus 为 NULL,父进程将不关心子进程的退出状态。
  • 返回值:返回已退出的子进程的PID。如果没有子进程,返回 -1
例子:
pid_t pid = wait(NULL); // 等待任一子进程退出,不关心状态
  • 如果没有子进程,调用 wait() 会失败,返回 -1,并设置 errno 为 ECHILD,表示没有子进程。
为什么使用 wait()

wait() 的主要作用是回收子进程资源,防止出现“僵尸进程”。如果父进程不调用 wait(),子进程退出时,它的进程表项仍然保留在操作系统中,直到父进程明确回收它。这样的进程称为僵尸进程。


4. 文件操作与同步

在多进程环境中,若多个进程共享同一个文件进行写操作,必须考虑到进程间的同步问题,避免出现竞争条件。我们可以通过以下步骤来实现:

  1. 父进程和子进程分别打开同一个文件进行写入。
  2. 每个进程写入10条数据,标明它们分别是由不同进程写入的。
  3. 父进程在子进程写完数据后,进行收尸操作,回收子进程资源,防止僵尸进程。
程序实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>void write_to_file(const char *filename, const char *text) {int fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, 0644);if (fd == -1) {perror("Failed to open file");exit(1);}write(fd, text, strlen(text));close(fd);
}int main() {const char *filename = "output.txt";pid_t pid;for (int i = 0; i < 2; i++) {pid = fork();if (pid == 0) {// 子进程for (int j = 0; j < 10; j++) {char text[100];snprintf(text, sizeof(text), "Child %d writes line %d\n", getpid(), j + 1);write_to_file(filename, text);}_exit(0); // 使用 _exit() 防止调用 exit() 时引发资源清理} else if (pid < 0) {perror("Fork failed");exit(1);}}// 父进程等待子进程结束for (int i = 0; i < 2; i++) {wait(NULL); // 收尸}printf("Parent process is done.\n");return 0;
}

查看全部

程序说明:
  1. 文件操作:父进程和子进程分别使用 open() 打开文件并进行写操作。写操作使用 O_APPEND 标志,这样每次写入的数据都会被追加到文件末尾。
  2. fork() 创建两个子进程:每个子进程都会写入10行数据。
  3. wait() 阻塞父进程:父进程在两个子进程都结束后再退出,确保在父进程退出之前回收所有子进程资源,避免僵尸进程。

5. 总结

通过本文的学习,我们深入了解了C语言中的进程管理,包括 fork()execvp()wait() 等函数的使用。通过这些机制,我们可以实现父子进程的创建、程序的执行以及资源的回收。

在实际编程中,fork() 和 exec() 是两个非常常用的系统调用,父进程通过 fork() 创建子进程,而子进程通过 exec() 执行新的程序。在多进程环境下,我们还必须关注僵尸进程的管理,确保父进程使用 wait() 正确地回收子进程资源。

文件操作中的同步也是一个重要课题,当多个进程访问同一文件时,我们必须小心同步问题,避免数据竞争。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词