1.fork函数介绍
一个进程,包括代码、数据和分配给进程的资源。
fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
包含的头文件:
#include <sys/types.h>
#include <unistd.h>
函数原型:(man 2 fork查看)
pid_t fork(void);
两个返回值:
=0:当前进程为子进程
>0:当前进程为父进程
‐1,出错
用户数据一样,进程ID不一致。因为进程ID存在任务控制块(PCB)中,PCD又是再内核中的
2.fork函数使用
去编写一个fork.c文件,然后使用fork函数,从输出结果可以看出,子进程是等父进程运行结束后运行的,但实际不是都是先执行父进程再执行子进程的
修改一下代码,再使用fork函数之前先输出i
多次执行之后会出现子进程打印到命令行去了。因为shell命令也是一个进程,它不知道fork生成了一个子进程,有多个进程就会抢占资源,所以有了这种现象
3.fork小结
1.fork函数的返回值
=0:当前进程为子进程
>0:当前进程为父进程
‐1,出错
2.子进程创建成功之后,子进程的执行位置,fork之后执行
3.父子进程的执行顺序, 不一定父进程先执行
4.如何区分父子进程,通过返回值区分
4.vfork
vfork也可以创建进程,与fork有什么区别呢?
区别一:vfork可以直接使用父进程存储空间,不拷贝
区别二:vfork可以保证子进程先运行,当子进程调用exit退出后,父进程才执行
一下面代码为例,子进程执行后,父进程执行打印出的cnt的值是3,如果把子进程中退出的方式exit换成break跳出while循环,然后子进程执行代码自然结束,父进程打印出的cnt值就不是3,
为什么这样子呢,这就要讲到程序的退出了
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
pid_t pid;
int cnt=0;
pid=vfork();
if(pid>0)
{
while(1)
{
printf("cnt= %d\n",cnt);
sleep(1);
}
}
if(pid>0)
{
while(1)
{
cnt++;
printf("cnt= %d\n",cnt);
sleep(1);
if(cnt==3)
{
exit(0);
}
}
}
}
5.程序退出
1.正常退出
1.main函数调用return
2.进程调用exit(),标准C库
3.进程调用 _exit() 或者 _Exit(),属于系统调用
补充:
4.进程最后一个线程返回
5.最后一个线程调用pthread_exit
2.异常退出
1.调用abort函数
2.当进程收到某些信号时,比如ctrl +C
3.最后一个线程对取消(cancellation)请求做出相应
不管进程如何终止,最后都会执行内核中的同一段代码,这段代码和相应进程关闭所有打开描述符,释放它所使用
的存储器等。
对上述任一种终止情形,我们都希望终止进程能够通知其父进程它是如何终止的。对于三个终止函数(exit, _exit和 _ Exit),实现这一点的方法是,将其退出状态(exit status)作为参数传送给函数,在异常终止情况下,内核(不是进程本身)产生一个指示其异常终止原因的终止状
(termination status)。在任意一种情况下,该终止进程的父进程都能用wait或waitpid函数取得终止状态。
6.ps命令
ps:查看进程信息
a : 显示现行终端机下的所有程序,包括其他用户的程序
u: 以用户为主的格式来显示程序状况
x: 显示所有程序,不以终端机来区分
ps aux 与ps ajx 差不多,但是ajx显示的更多一点
写一个hello.c文件,去执行。sleep(1)是间隔1s,现象就是每隔1s打印hello world
通过ps aux | grep hello 刚才生成的可执行程序式hello(|是管道的意思,例如,管道左边在读,右边在写)
./是可执行的,hello是正在执行,2363就是下面我们用kill停止程序用的程序编号
7.kill命令
kill可将指定的信息送至程序。预设的信息为SIGTERM(15),可将指定程序终止。若仍无法终止该程序,可使用SIGKILL(9)信息尝试强制删除程序。程序或工作的编号可利用ps指令或job指令查看。
-a:当处理当前进程时,不限制命令名和进程号的对应关系;
-l <信息编号>:若不加<信息编号>选项,则-l参数会列出全部的信息名称;
-p:指定kill 命令只打印相关进程的进程号,而不发送任何信号;
-s <信息名称或编号>:指定要送出的信息;
-u:指定用户。
1-31是我们比较常用的
用kill停止写到hello.c
kill -9 2363