Linux主要提供了fork、vfork和clone三种方法来创建进程。
01 进程获取
- getpid():用来取得目前进程的进程ID,而getppid可以得到父进程的ID;
许多程序利用取到的此值来建立临时文件,以避免临时文件相同带来的问题。 - getegid():获取执行有效的组识别码。
02 启动进程:fork()
fork()用于创建子进程,创建新的进程
表头文件:#include<sys/types.h>
返回值:在父进程中返回子进程的进程号,在子进程中返回0,错误返回-1
-
子进程完全复制父进程的资源,复制出来的子进程用自己的task_struct结构和PID;
-
子进程独立于父进程,具有良好的并发性;
-
子进程获得父进程的数据空间、堆和栈的副本,这些都是副本,父子进程并不共享这部分的内存(也就是说,子进程对父进程中的同名变量进行修改并不会影响其在父进程中的值)。
实际上,更准确来说,Linux 的 fork() 使用是通过写时拷贝 (copy- on-write) 实现。
写时拷贝是一种可以推迟甚至避免拷贝数据的技术。
内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。
只用在需要写入的时候才会复制地址空间,从而使各个进行拥有各自的地址空间。
也就是说,资源的复制是在需要写入的时候才会进行,在此之前,只有以只读方式共享。
注意:fork之后父子进程共享文件,
fork产生的子进程与父进程相同的文件文件描述符指向相同的文件表,引用计数增加,共享文件偏移指针。
示例代码
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main() {
int num=10;
//创建子进程(创建当前进程的一个子进程)
pid_t pid=fork();
//判断是父进程还是子进程
if(pid>0) {
//fork() 在父进程中返回子进程的进程号,在子进程中返回0,错误返回1
printf("当前是父进程, pid: %d, ppid: %d\n",getpid(),getppid());
printf("parent num: %d,\n",num);
num+=10;//修改num的值
printf("parent num+=10: %d,\n",num);
} else if(pid==0) {
//当前是子进程
printf("当前是子进程, pid: %d, ppid: %d\n",getpid(),getppid());
printf("child num : %d\n", num);
num += 200;
printf("child num += 100 : %d\n", num);
}
// for循环(父进程和子进程都会执行)
for(int i = 0; i < 3; i++) {
printf("i : %d , pid : %d\n", i , getpid());
sleep(1);
}
return 0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/2c5f46b3538115098d7a591e565da9cf.png)
vfork()用于创建新的子进程
表头文件:#include<unistd.h>
使用vfork创建的子进程与父进程共享内存空间,也就是说,子进程完全运行在父进程的地址空间上,如果这时子进程修改了某个变量,将影响带父进程。
注意:用vfork()创建的子进程必须显示调用exit()来结束,否则进程不能结束,而fork不存在这个情况。
system 用于执行shell命令
头文件:include<stdlib.h>
system()会调用fork()函数产生子进程