进程创建:
fork函数:
#include<unistd.h> pid_t fork(void); 返回值: 子进程返回0,父进程返回子进程的进程id,出错返回-1.
fork之后,子进程是父进程的副本。子进程获得父进程数据空间、堆和栈的副本。值得注意的是,这是子进程所拥有的副本,父进程和子进程并不共享这些存储空间部分。也就是说,子进程对变量做出的改变并不影响父进程。
下面是一段关于fork的简单代码
#include<stdio.h> #include<sys/types.h> #include<unistd.h> int main() { int ret = fork(); if(ret<0) { printf("fork"); return 1; } else if(ret == 0) printf("i am child:%d!,ret:%d\n",getpid(),ret); else printf("i am father:%d!,ret:%d\n",getpid(),ret); sleep(1); return 0; }
fork之后是先执行父进程还是先执行子进程是不确定的,取决于内核所使用的调度算法。如果我们想要子进程先运行,可以让父进程先sleep,等到子进程结束后再执行父进程。
写时拷贝:通常,父子代码共享,父子不再写入时,数据也是共享的,当任意一方试图写入时,便以写时拷贝的方式各自拷贝一份副本。
fork常规用法:
1.一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如:父进程等待客户端请求,子进程来处理请求。
2.一个进程要执行一个不同的程序。例如:从fork返回之后,执行exec函数。
fork调用失败的原因:
1.系统中有太对进程
2.实际用户的进程数超过了限制。
vfork函数:
vfork也用来创建子进程,而子进程和附近曾共享地址空间。fork的子进程具有独立的地址空间。
vfork保证子进程先进行,在它调用exec或exit之后父进程才有可能被调度。当子进程调用这两个函数中的任意一个时,父进程会回复运行。
进程终止:
进程退出场景:
1.代码运行完毕,结果正确
2.代码运行完毕,结果不正确
3.代码异常终止
进程正常终止:五种
1.从main函数返回
2.调用exit函数
3.调用_exit_Exit函数
4.进程的最后一个线程在启动例程中执行return语句
5.进程的最后一个线程调用pthread_exit语句
进程异常退出:三种
1.调用abort函数
2.进程接收到某些信号时。如:ctrl + c
3.最后一个线程对取消请求做出相应。
不管进程如何终止,最后都会执行内核中的同一段代码。这段代码为相应进程关闭所有打开描述符,释放它所使用的存储器等。
: