一、阅读实例代码fork1, 并编辑、编译、运行,记录程序的运行结果,尝试给出合理的解释。
fork()是UNIX或类UNIX中的分叉函数,fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程.这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本.当调用fork()时,将执行以下动作:
向系统申请一个新PID创建子进程,复制父进程的PCB,获得父进程的数据空间、堆、栈等资源的副本在父进程中返回子进程的PID,在子进程中返回0执行完以上动作后,父进程和子进程便开始并发执行了。
当父进程调用 fork()后,fork()得到一个新的 PID并进行复制副本,复制 PCB 等一系列子进程的准备工作后,此时父子两个进程将并发执行,这时候共有两个 fork()存在,父子进程中都在等待着 fork()函数的最后一步:返回值.这时候父进程中的 fork()将返回子进程的 PID,而子进程中的 fork()返回 0,由于子进程在创建时几乎复制了父进程的一切,自然也就包括了父进程的堆栈段,fork()在两个进程中都存在着,所以一共可以返回两次。即在父进程中返回一次,在子进程种种再返回一次。
所以printf(“I’m the child.\n”);
printf(“I’m the parent.\n”); 执行了两次。
二、阅读实例代码proc1.c,编辑、编译、运行,记录运行结果,解释运行结果。
fork()后立即调用exec()函数,fork()的实际开销就是复制父进程的页表以及给子进程创建惟一的进程描述符。在一般情况下,进程创建后都会马上运行一个可执行的文件
用exec函数可以把当前进程替换为一个新进程,且新进程与原进程有相同的PID。exec名下是由多个关联函数组成的一个完整系列,
头文件<unistd.h>
execl()其中后缀"l"代表list也就是参数列表的意思
perror是错误输出函数,在标准输出设备上输出一个错误信息。
fork函数返回两个值,对于子进程,返回0; 父进程,返回子进程ID. 所以用execl(“/bin/ls”,”ls”,0);执行bin目录下的ls命令
if(fork()==0)
{子进程执行的代码段;}
else
{父进程执行的代码段;}
I'm the parent.//执行父进程
program end.//父进程结束
I'm the child.//执行子进程
三、
PID
一个整数,它是进程唯一的标识符,又称进程号。
PID按进程创建的顺序赋值。PID 的分配机制则因系统而异,一般从 0 开始,然后顺序分配。
PPID
父进程的PID
fprintf()和printf()一样工作;
printf是打印输出到屏幕,fprintf是打印输出到文件。
fprintf()的返回值是输出的字符数,发生错误时返回一个负值。
使用 strerror () 将错误代码转换成对应的文信息.<errno.h> 头文件中有一个 errno 宏,它就用来存储错误代码,当系统调用或者函数调用发生错误时,就会将错误代码写入到 errno 中,再次读取 errno 就可以知道发生了什么错误。
#include <sys/types.h>基本系统数据类型是Unix/Linux系统的基本系统数据类型的头文件。
exit(0):正常运行程序并退出程序,调用时程序运行正常结束;
exit(1):非正常运行导致退出程序,调用时程序运行非正常结束;
getpid()返回的是当前进程的pid,getppid()返回的是当前进程的父进程的pid。
Linux 操作系统的启动首先从 BlOS 开始,然后由 Boot Loader 载入内核,并初始化内核。内核初始化的最后一步就是启动 init 进程。这个进程是系统的第一个进程, PID 为1,又叫超级进程,也叫根进程。它负责产生其他所有用户进程。所有的进程都会被挂在这个进程下,如果这个进程退出了,那么所有的进程都被 kill如果一个子进程的父进程退了,那么这个子进程会被挂到PID1下面。
fork1
#include<stdio.h>
#include<unistd.h>
main( ) {
int pid;
pid=fork();
if (pid==-1)
{
printf(“fork failed.\n”);
return;
}
printf(“I’m the child.\n”);
printf(“I’m the parent.\n”);
return;
}
proc1
/*proc1.c演示有关进程操作*/
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <errno.h>
int main(int argc,char **argv)
{
pid_t pid,old_ppid,new_ppid;
pid_t child,parent;
parent=getpid(); /*获得本进程的PID*/
if((child=fork())<0){
fprintf(stderr,"%s:fork of child failed:%s\n",argv[0],strerror(errno));
exit(1);
}
else if(child==0){ /*此时是子进程被调度运行*/
old_ppid=getppid();
sleep(2);
new_ppid=getppid();
}
else {
sleep(1);
exit(0); /*父进程退出*/
}
/*下面仅子进程运行*/
printf("Original parent:%d\n",parent);
printf("Child:%d\n",getpid());
printf("Child's old ppid:%d\n",old_ppid);
printf("Child's new ppid:%d\n",new_ppid);
exit(0);
}
fork2
Fork2.c
#include<stdio.h>
include<unistd.h>
main()
{ int pid;
pid=fork();
if(pid==0) {
printf(“I’m the child.\n”);
execl(“/bin/ls”,”ls”,0);
perror(“exec error.\n”);
} else if(pid>0)
printf(“I’m the parent.\n”)
else printf(“fork failed.\n”);
printf(“program end.\n”);
}