# 程序员用进程
作为一名程序员,在编写程序时肯定会用到多进程,多线程,那么在应用上,我们要怎么从内核基础知识的角度来看待多进程与多线程呢?
## fork()函数
我们在开发中,创建子进程大概率会用到fork()函数。这时,我们从kernel的基础知识上可知,创建的子进程和父进程有各自独立的进程地址空间,但是共享物理内存资源,包括进程上下文,进程堆栈,内存信息,打开的文件描述符,进程优先级,根目录,资源限制,控制终端等。
说完相同,接下来再聊聊子进程和父进程的差别:
1. 子进程和父进程的进程ID不同
2. 子进程不会继承父进程的内存方面的锁,如mlock();定时器,如settimer(),alarm();信号量,如semop();
在使用fork()函数时,代码如下:
```
pid_t fork();
```
fork()函数返回两次:一次是在父进程中返回正整数,即子进程的PID,另一次是在子进程中返回0。当然,如果返回值是-1,则创建失败了~~
### 典型应用
1. 实现多进程程序:通过fork()函数,可以方便地创建多个进程,每个进程可以独立地执行不同的任务。这是实现并发执行和并行处理的一种常见方式。
2. 实现管道和重定向:fork()函数可以和管道(pipe())以及重定向(dup())等技术结合使用,实现进程间通信和数据交换。例如,可以使用fork()函数创建一个子进程,然后通过管道将子进程的输出传递给父进程进行处理。
3. 实现系统守护进程:守护进程(Daemon)是在后台运行且不与前台交互的进程。通过fork()函数,可以创建一个子进程,让子进程成为守护进程,而父进程退出。这样,子进程就不会受到父进程退出状态的影响,并且可以在后台独立运行。
4. 实现网络服务器:网络服务器通常需要同时处理多个客户端请求。通过fork()函数,可以为每个客户端请求创建一个子进程,每个子进程独立地处理一个请求,从而实现并发处理。不过,我在实际项目中使用的是libuv库,通过异步复用IO来实现的。
## vfork()函数
vfork()函数与fork()函数类似,但vfork()函数会导致父进程一直阻塞,直到子进程调用exit()或execve()。
### 典型应用
去查询了一下,vfork()基本是一个被弃用的状态。其原因是
> 在 vfork 和随后的 exec 之间的若干个毫秒内,万一某些进程权限被修改了,就会导致 exec 出来的进程获得了非预期的权限
而且,在“写时复制”的技术背景下,其原有的优势也没有那么明显了。时代的进步还是会把一些东西碾压在车轮之下啊!
## clone()函数
clone()函数,通常用于创建用户线程,其功能强大,可以传递众多参数,配置非常灵活。当我们在创建进程时,需要极其精细的时候,则使用clone()函数。当然,fork()函数在内核中也是使用clone()函数来复制父进程的上下文信息的。
## 总结
在多数情况下,做为程序员不需要过多的关心内核的知识,毕竟内核都为我们考虑了,还很周全。只是在对系统进行适配性的优化,深挖系统潜能的时候,内核知识便尤为重要了。
一本书,相对于内核知识来说,太少。阅读一本书,阅读一本很厚的书,需要耐心,需要时间,需要精力。这便是Linux内核的特点,这也是Linux内核的魅力。在未来的日子里,我仍然会再次阅读《奔跑吧Linux内核》,不断提高自身知识,继续分享我的读书心得。
## 致谢
谢谢EEWORLD论坛,谢谢本书作者笨叔,感谢一直关注我的网友们。