当前位置: 首页 > article >正文

Linux 进程终止

Linux 进程终止

    • 引言
    • 1. 正常终止
      • 1.1 在 `main()` 函数中使用 `return` 语句
      • 1.2 调用 `exit()` 函数
      • 1.3 使用 `_exit()` 或 `Exit()` 函数
        • 疑问:`_exit()` 和 `Exit()` 的应用场景是什么?
      • 1.4 最后一个线程退出时终止进程
    • 2. 异常终止
      • 2.1 调用 `abort()` 函数
      • 2.2 接收到信号
      • 2.3 父进程终止子进程
    • 3. 检查进程的终止状态
      • 3.1 在 Shell 中查看状态
    • 4. `atexit()` 函数:注册退出函数
    • 5. `exit()`, `_exit()` 和 `Exit()` 的区别

引言

在操作系统中,进程是程序的执行实例,而理解进程的终止机制对开发者和系统管理员至关重要


1. 正常终止

1.1 在 main() 函数中使用 return 语句

最常见的进程正常终止方式是通过 main() 函数中的 return 语句。当 main() 函数执行完毕时,进程会正常退出并将状态返回给操作系统。

代码示例:

#include <stdio.h>

int main() {
    printf("Hello, world!\n");
    return 0;  // 正常终止进程
}
  • 退出状态:通常是 0(表示成功终止)

1.2 调用 exit() 函数

exit() 函数用于在程序执行过程中主动终止进程。它可以在任何位置调用,而不仅仅是 main() 函数结束时。

代码示例:

#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("This is a program that will exit now.\n");
    exit(0);  // 正常终止进程
}
  • 退出状态:作为参数传递,通常是 0(表示成功终止)

1.3 使用 _exit()Exit() 函数

在某些情况下,exit() 会执行一些缓冲区清理工作。若需要直接终止进程并跳过清理操作,可以使用 _exit()Exit()

代码示例:

#include <unistd.h>
#include <stdlib.h>

int main() {
    write(1, "This will call _exit() directly.\n", 33);
    _exit(0);  // 直接终止进程,不执行缓冲区刷新等清理工作
}
疑问:_exit()Exit() 的应用场景是什么?

这两个函数的特点是直接结束进程,跳过缓冲区刷新和清理工作。通常用于以下场景:

  • 在多线程程序中,子线程可以通过 _exit()Exit() 直接退出,而不需要执行 I/O 刷新等清理任务。
  • 在进程需要紧急退出时,例如遇到严重错误或崩溃,使用 _exit()Exit() 可以避免因执行清理操作导致的额外延迟。

1.4 最后一个线程退出时终止进程

在多线程程序中,整个进程的终止通常由最后一个线程退出时触发。可以通过主线程的返回或者调用 pthread_exit() 来实现。

代码示例:

#include <pthread.h>
#include <stdio.h>

void* thread_func(void* arg) {
    printf("Thread started\n");
    pthread_exit(NULL);  // 线程退出
}

int main() {
    pthread_t thread;
    pthread_create(&thread, NULL, thread_func, NULL);
    pthread_join(thread, NULL);  // 等待线程结束
    printf("Main thread ends\n");
    return 0;
}

2. 异常终止

2.1 调用 abort() 函数

进程在遇到异常情况时,可能会进行异常终止。最直接的方式是调用 abort() 函数,该函数会立即终止进程,并产生核心转储文件。

代码示例:

#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("This will abort the program.\n");
    abort();  // 异常终止进程
    return 0;  // 不会执行到这里
}

2.2 接收到信号

进程还可以因为收到信号而终止。常见的信号包括 SIGKILLSIGTERM,它们会通知进程停止运行。进程的信号处理方式决定了它是正常终止还是异常终止。

代码示例:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void sig_handler(int sig) {
    printf("Received signal %d\n", sig);
    _exit(0);  // 接收到信号时终止进程
}

int main() {
    signal(SIGINT, sig_handler);  // 捕获 SIGINT 信号(Ctrl+C)
    while(1) {
        printf("Running... Press Ctrl+C to terminate\n");
        sleep(1);
    }
    return 0;
}

2.3 父进程终止子进程

有时,进程会被父进程终止。当子进程出现错误或不再需要时,父进程可以发送终止信号,或者直接通过调用 exit() 终止它。

代码示例:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

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

    if (pid == 0) {  // 子进程
        printf("Child process running...\n");
        sleep(2);  // 模拟子进程运行
        printf("Child process terminating...\n");
        exit(0);  // 子进程正常退出
    } else {  // 父进程
        wait(NULL);  // 父进程等待子进程终止
        printf("Parent process terminating...\n");
        exit(0);  // 父进程退出
    }

    return 0;
}

3. 检查进程的终止状态

当一个进程终止后,我们通常需要查看其退出状态,以判断它是成功终止还是遇到了错误。可以通过 shell 命令来查看进程的退出状态。

3.1 在 Shell 中查看状态

在类 Unix 系统中,可以使用 echo $? 命令来查看最近执行的命令的退出状态。这将返回进程的退出码。

$ ./my_program
$ echo $?
0  # 0 表示程序成功终止

4. atexit() 函数:注册退出函数

在 Linux 中,我们还可以使用 atexit() 函数来注册当进程退出时自动调用的函数。最多可以注册 32 个退出函数。这些函数将在程序终止时反向调用,非常适合用于释放资源、保存数据等清理操作。

代码示例:

#include <stdio.h>
#include <stdlib.h>

void cleanup() {
    printf("Cleanup function called during exit\n");
}

int main() {
    atexit(cleanup);  // 注册退出时调用的函数
    printf("Program is running...\n");
    return 0;  // 退出时会调用 cleanup 函数
}

5. exit(), _exit()Exit() 的区别

尽管 exit()_exit()Exit() 都用于终止进程,但它们之间有一些显著的区别,尤其是在执行清理工作方面。下面是它们的简要对比:

  • exit():执行标准的清理工作(例如刷新 I/O 缓冲区),然后终止进程。
  • _exit():直接终止进程,不执行标准清理工作。
  • Exit():与 _exit() 类似,但通常用于多线程程序中,可以直接退出而不执行清理工作。

http://www.kler.cn/a/533120.html

相关文章:

  • Nacos 的介绍和使用
  • 系统URL整合系列视频二(界面原型)
  • vscode软件操作界面UI布局@各个功能区域划分及其名称称呼
  • 普罗米修斯监控服务搭建位置全解析:权衡与抉择
  • 大模型领域的Scaling Law的含义及作用
  • deepseek接入pycharm 进行AI编程
  • BUU13 [极客大挑战 2019]BabySQL 1
  • DeepSeek-R1大模型学习笔记
  • 用Python实现SVM分类器:从数据到决策边界可视化,以鸢尾花数据集为例
  • DeepSeek 本地部署全攻略
  • Java使用Jsoup处理报文简单样例
  • CSS in JS
  • 【LeetCode: 922. 按奇偶排序数组 II + 双指针】
  • 个人c项目 java项目解释
  • 力扣 45. 跳跃游戏 II
  • 3. k8s二进制集群之负载均衡器高可用部署
  • 7. k8s二进制集群之Kube ApiServer部署
  • Oracle日常管理(8)——OS日常管理(1)
  • WPS计算机二级•幻灯片的配色、美化与动画
  • Day 28 卡玛笔记
  • JAVA篇12 —— 泛型的使用(待完善)
  • 多线程的常用方法
  • 高等代数笔记—域与一元多项式
  • 中国证券基本知识汇总
  • HTB:Administrator[WriteUP]
  • 【01-Qt-C++-android】