嵌入式的学习笔记——Linux中的fork函数

昨天晚上调试那个服务器日志时,突然发现进程数多到看花眼,一查才明白fork玩脱了。
比如有一次在 /tmp 下面写个小脚本,想用 fork 实现同时监控两个文件,结果写完 pid_t pid = fork(); 后忘记加 if (pid == 0),直接 system("cat file1 .txt") 和 system("cat file2 .txt"),最后两个文件内容全是一样的,因为都在子进程里运行了。

这让我想起 Demo1 里那个 count++ 的例子。
当时看代码时还觉得挺好,子进程和父进程独立计数,结果自己手贱把 count 改成全局变量,结果父进程和子进程都疯狂打印同一个值,因为全局变量在 fork 后还是共享的啊。

不过 Demo2 里那个双层 fork 就有意思了。
我在宿舍的虚拟机里运行过,第一次 fork 后,父进程的 printf 打印了 1 parent,子进程的 printf 打印了 0child,第二次 fork 后,父进程又多打印了 2 parent,子进程又多打印了两个 1 child 和 0child。
最后总共有 5 行输出,但仔细数会发现进程 ID 是连续的(假设第一次 fork 返回 1 2 3 4 5 ,那子进程是 5 ,第二次 fork 后父进程是 6 ,子进程是 7 和 8 )。
这就说明每次 fork 都是在上一个子进程的基础上再分叉,所以进程数是指数级增长的。

等等,还有个事。
我之前用 fork + exec 切换程序时,忘了在子进程中 waitpid() 等待子进程退出,结果父进程直接跑飞了,终端里全是 Z+ 进程。
系统提示 kill -9 才搞定的,当时屏幕都快黑了。

突然想到,如果 fork 后父进程和子进程都去改同一个共享文件,会出现什么情况?比如 fork() 后,父进程写 echo "p" >> /tmp/log.txt,子进程写 echo "c" >> /tmp/log.txt,那 /tmp/log.txt 里会不会是 pc 还是 ccp?这得实验一下。

现在 man 2 fork 看着挺明白,但真用起来总出错。
比如有一次忘了加 if (pid > 0),结果父进程也跑进了子进程的代码块,最后系统里多出了几个一模一样的子进程,CPU 占用率直接飙升到 1 00%。

不过 fork 真挺有意思的。
比如用 ps aux | grep child 可以看到所有子进程,但 kill 时得知道具体 PID,不然 kill -9 $(pgrep child) 这种写法很容易误杀父进程。

有时候觉得 Linux 进程管理像搭积木,fork 是块基础砖,exec 是换面儿的纸,wait 是清理废料的扫帚。
但光有这些还不够,还得会 nice、renice、nice2 这些小技巧,不然进程跑太快把系统别卡了就麻烦了。

话说回来,如果子进程又 fork 子进程,那 getppid() 会变成什么?父进程的 getppid() 又会指向谁?这得找个时间再试试。

Linux进程通信实验报告

说实话,做这实验的时候我挺有意思的。
你想想,一台2 5 6 MB内存的破机器,装着RedHatLinux9 ,跑起三个进程——父进程一个,两个子进程各一个——当时我就在想,这系统得吃多少资源啊。
不过话说回来,Linux在资源紧张的时候还挺有韧劲的。

当时我手把手带实习生做这个,先搞fork函数。
说实话,我当年学Linux的时候,fork函数把我绕得够呛。
你想想,一个进程分身乏术,突然冒出两个新进程,这中间的各种内存拷贝、上下文切换,光想就头大。
但实验里你得这么干:父进程用fork(),然后两个子进程各自判断一下自己是不是fork的产物。
代码写完,用getpid()看PID,父进程和子进程的PID肯定不一样,这就是最直观的证明。

重点在lockf调用上。
我当时在机房调试,写完代码编译运行,结果屏幕上字符乱成一锅粥。
父进程的"a"和两个子进程的"b"、"c"混在一起,根本分不清谁是谁。
我赶紧在代码里加锁,用lockf系统调用,把共享资源(就一个屏幕输出)锁住。
加了锁之后,运行程序,屏幕上先出"a",然后停顿一下,再出"b",最后出"c"。
这时候观察就清晰多了——顺序执行,但本质上是并发。

有意思的是,内存只有2 5 6 MB,三个进程同时跑,系统调度得超有意思。
有时候"a"刚出,"b"马上跟着,有时候又隔了挺久。
我当时也没想明白这是啥原因,后来才知道是Linux的调度算法在搞鬼。
反正这实验挺直观的,虽然简单,但把并发和顺序执行的区别、临界资源争用这些抽象概念,一下子具象化了。
你想想,要是用伪代码讲,学生可能根本没概念;但让他们自己写代码,看进程跑出乱码,再想办法用锁解决,这种体验就完全不一样了。

数据我记得是RedHat9 那时候,系统负载跑满1 00%时,三个进程还能勉强运行,但响应肯定慢。
这块我没亲自跑过6 4 位的,但建议你核实下现在的系统表现。
反正做这实验,关键不是看内存够不够,是看能不能把并发、进程、锁这些概念串起来。

【LINUX】主进程、父进程、子进程、守护进程的概念

结论:
主进程:程序启动的起点,负责启动和协调其他进程。

父进程:主进程创建的进程,管理子进程。

子进程:由主进程或父进程创建,执行特定任务。

守护进程:后台运行,独立于用户会话,提供持续服务。

理解进程类型对Linux环境至关重要,维护系统稳定和功能。