中国建设监理协会网站会员专区全网有哪些网站可以做淘客
2026/2/16 0:05:30 网站建设 项目流程
中国建设监理协会网站会员专区,全网有哪些网站可以做淘客,企业门户网站 源码,seo网站建设优化什么意思【Linux】从 fork 到进程终止#xff1a;写时拷贝细节与常见退出方式 Linux 进程创建#xff08;fork#xff09;与终止#xff08;exit/kill#xff09;是操作系统中最核心、最常被考察的机制之一。 本文重点讲解 fork 的写时拷贝#xff08;Copy-On-Write, COW#x…【Linux】从 fork 到进程终止写时拷贝细节与常见退出方式Linux 进程创建fork与终止exit/kill是操作系统中最核心、最常被考察的机制之一。本文重点讲解fork 的写时拷贝Copy-On-Write, COW实现细节以及进程终止的各种方式正常/异常/强制结合内核视角、常见陷阱与生产实践。1. fork() 的本质与写时拷贝COW机制1.1 fork() 做了什么fork()是 POSIX 标准中创建新进程的系统调用返回值子进程返回 0父进程返回子进程 PID0失败返回 -1errno最关键的一点子进程是父进程的几乎完整副本包括代码段、数据段、堆、栈、打开的文件描述符、信号处理、环境变量等。传统实现很早的 Unix会直接复制整个地址空间 →极其昂贵内存拷贝 时间。1.2 现代 Linux 如何优化→ 写时拷贝Copy-On-WriteLinux从很早版本开始采用COW机制fork 时不复制物理页面而是复制页表page table子进程的页表项指向父进程相同的物理页面所有用户态可写页面大多数数据/堆/栈被标记为只读read-only内核在页表中设置写保护位读操作直接访问共享的物理页面 →零拷贝速度极快第一次写操作任一进程触发页面故障page fault内核检测到写保护 → 分配一个全新物理页面把原页面内容复制到新页面更新当前进程的页表 → 指向新页面可写父/子进程各自拥有独立的副本一句话总结fork 后父子共享物理内存直到其中一方写时才真正复制该页。1.3 COW 的典型表现代码演示#includestdio.h#includeunistd.h#includesys/wait.hintglobal_var100;// 数据段intmain(){intstack_var200;// 栈pid_tpidfork();if(pid0){// 子进程printf(子进程: global%d, stack%d\n,global_var,stack_var);global_var999;// 写 → 触发 COW该页被复制stack_var888;printf(子进程修改后: global%d, stack%d\n,global_var,stack_var);}else{// 父进程wait(NULL);printf(父进程: global%d, stack%d\n,global_var,stack_var);// 父进程看到的仍是 100 和 200COW 后子进程修改的是自己的副本}return0;}输出子进程: global100, stack200 子进程修改后: global999, stack888 父进程: global100, stack200结论父子进程修改的是各自独立的副本不互相影响。1.4 COW 的优点与代价优点fork 极快只需复制页表 标记写保护内存利用率高大量 fork 后 exec 的场景如 shell、Apache prefork 模式几乎不额外耗内存代价 / 副作用写操作会触发页面复制 →写放大尤其是大进程 fork 后频繁写内存时多进程同时写同一页 → 每个进程都复制一份内存碎片可能增加生产建议尽量 fork 后尽快 exec经典用法避免 COW 带来的写放大高并发服务器避免 fork 模型 → 改用线程池 / 事件驱动 / 多进程预 fork accept(2) 复用2. 进程终止的常见方式Linux 进程退出有多种路径影响退出码、资源释放、信号处理、atexit/on_exit等清理函数是否执行。方式系统调用/信号是否调用 atexit()是否发 SIGCHLD是否可捕获典型退出码备注 / 适用场景main 返回exit()是是—返回值最正常退出exit() / _exit()exit_group() / exit是 / 否是—参数exit 调用 atexit_exit 不调用pthread_exit()—否仅线程否——仅退出当前线程主线程仍存活return from mainexit()是是—返回值等价于 exit()SIGTERM (kill -15)—是若 handler 调用 exit是可捕获通常 143优雅终止默认行为SIGKILL (kill -9)—否是不可捕获通常 137强制杀死不可拦截SIGABRT (abort())—否核心转储是可捕获通常 134断言失败等段错误等异常SIGSEGV 等否是可捕获通常 139核心转储关键区别exit()调用 atexit/on_exit 注册的清理函数 → 刷新 stdio 缓冲区 → 关闭打开的文件fclose→ 然后调用 _exit()_exit()直接系统调用 exit不做任何用户态清理缓冲区可能丢失SIGTERM默认行为是终止进程但可以捕获并做清理调用 exit()SIGKILL内核强制杀死无法捕获、无法清理脏数据可能残留退出码约定Shell 中 $?正常退出0 ~ 255用户定义被信号杀死128 信号编号SIGTERM (15) → 143SIGKILL (9) → 137SIGSEGV (11) → 1393. 生产中最常见的终止流程推荐#includestdio.h#includestdlib.h#includesignal.h#includeunistd.hstaticvoidcleanup(void){printf(atexit 清理关闭文件、释放资源...\n);}staticvoidsigterm_handler(intsig){printf(收到 SIGTERM进行优雅退出...\n);// 可以做保存状态、通知其他进程、关闭连接等exit(EXIT_SUCCESS);// 或 _exit(0) 看需求}intmain(){atexit(cleanup);signal(SIGTERM,sigterm_handler);// signal(SIGINT, sigterm_handler); // CtrlCprintf(进程运行中... PID%d\n,getpid());while(1){sleep(1);}return0;}测试# 终端1./a.out# 终端2kill-TERMpid# 优雅退出调用 atexitkill-9pid# 强制杀死不调用 atexit小结 面试/运维高频问题fork 后父子进程共享哪些资源文件描述符、mmap 共享内存等COW 触发条件是什么第一次写SIGTERM 和 SIGKILL 区别可捕获 vs 不可捕获为什么生产中常用 SIGTERM 优雅退出避免数据丢失、脏关闭如何防止子进程变成僵尸zombie父进程 wait/waitpid多线程程序中主线程 exit() 会怎样整个进程退出想继续深入哪个方向A. vfork() vs fork() vs clone() 区别B. 僵尸进程、孤儿进程的产生与处理C. 多线程信号分发与 pthread_killD. 内核视角task_struct → do_exit 流程E. 生产事故案例SIGKILL 导致数据损坏告诉我字母我们继续深挖

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询