1、fork与vfork
fork
#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
int main()
{
pid_t pid;
pid = fork();
if(pid<0)
printf("error in fork!\n");
else if(pid == 0)
printf("I am the child process,ID is %d\n",getpid())
else
printf("I am the parent process,ID is %d\n",getpid()
;
return 0;
}
fork创建出来的进程,父子进程没有必须的执行顺序,顺序也不是确定的,这取决于linux内核的调度算法。
fork在使用时会拷贝父进程的数据段和代码段,这就避免了在操作子进程数据时导致父进程数据发生改变。
vfork
#include<sys/types.h>
#include<unistd.h>
#include<stdio.h>
int main()
{
pid_t pid;
pid = vfork();
if(pid<0)
printf("error in fork!\n");
else if(pid == 0)
{
printf("I am the child process,ID is %d\n",getp
d());
exit(0);
}
else
printf("I am the parent process,ID is %d\n",getpid()
;
return 0;
}
vfork则是先执行子进程,且在子进程执行结束收回后,才能执行父进程的内容。
由于vfork是共享父进程的数据段,所以使用vfork时需格外注意子进程的回收情况,如果没有回收就会出现段错误。
区别:
- 执行顺序
- 是否共用数据段和代码段
对比分析
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main(void)
{
int data = 0 ;
pid_t pid ;
int choose = 0 ;
while((choose = getchar( ))!='q')
{
switch(choose)
{
case '1':
pid = fork( );
if(pid < 0 )
{
printf("Error !\n");
}
if(pid == 0 )
{
data++;
exit(0);
}
wait(pid); //wait用于回收子进程
if(pid > 0 )
{
printf("data is %d\n",data);
}
break;
case '2' :
pid = vfork( );
if(pid < 0 )
{
perror("Error !\n");
}
if(pid == 0 )
{
data++;
exit(0);
}
wait(pid);
if(pid > 0 )
{
printf("data is %d\n",data);
}
break;
default : break;
}
}
}
代码分析:
- 每当输入1的时候就会用fork创建子进程;
- 每当输入2的时候就会用vfork创建子进程;
- 子进程执行data++命令,父进程打印data值。
结果:
- 每次输入1的时候,并没有经过data++指令就将data的值打印了出来;每次输入2的时候,会先进行data++指定再打印data的值。
- 当多次重复输入1后,会发现data的值依旧是初始值;在多次重复输入2后,data的值都会加一。
结果分析:
结果一:
输入1,使用fork创建子进程。由于 fork创建的子进程,其子进程和父进程的执行顺序是不确定的,每次都是先执行了父进程,所以打印结果就没有经过data++这一步。
如果凑巧先执行了子进程,那么打印的结果就是data++。这个可以用sleep或wait函数去控制先执行子进程然后观察结果。
输入2,使用vfork创建子进程。vfork创建出的子进程,父进程会等子进程执行完且回收了子进程资源后再开始执行,所以每次都打印出的是data++。
结果二:
- 使用fork创建子进程时,fork会拷贝父进程的数据段和代码段。子进程在执行指令的时候也是在拷贝下来的数据段和代码段上执行,并不会影响到父进程的数据段内容,所以每一次data++都是在取父进程中的data值,且data值改变后不会影响到父进程中的data值。
- 使用vfork创建子进程时,vfork是共享父进程的数据段。子进程执行data++也就改变了父进程中的data值。
2、完善程序
要求:
实现一个程序启动另一个程序后自身仍然在运行,即在子进程中加载执行其他程序而父进程等待子进程结束后才结束。
参考
#include <error.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
/*接受键盘输入命令字符*/
/*创建子进程*/
if(创建失败)
/*打印“创建子进程失败”*/
else if (子进程){
/*用exec()加载程序执行输入的命令*/
}
else {
/*等待子进程信息*/
/*继续父进程的执行*/
}
}
#include <error.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <wait.h>
int main()
{
char a[20]={0};
pid_t pid;
/*接受键盘输入命令字符*/
printf("请输入程序名(命令路径):");
scanf("%s",a);
/*创建子进程*/
pid=fork();
if(pid<0)
/*打印“创建子进程失败”*/
{
printf("Error:fork fail!\n");
}
else if(pid==0)
{
/*用exec()加载程序执行输入的命令*/
execv(a,0);
_exit(0);
}
else
{
/*等待子进程信息*/
wait(NULL);
/*继续父进程的执行*/
printf("This is parent process\n");
}
}
Hello是在同目录下编辑出的一个Hello word程序。
3、父子进程通过无名管道传递三条消息
程序思路:
父进程发送信息,三条信息分三次发送;子进程也是一条信息一条信息的获取。父进程向管道写入一条信息后sleep1秒,然后等子进程读取出来,读完之后也sleep1秒如此往复。完成三条信息的传输。
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
pid_t pid;
char buf[3][35]={0};
int fd[2]={0};
int i;
char* context[]={"管道文件的测试程序开始","管道文件测试正在进行","管道通信测试结束"};
switch(pipe(fd))
{
case -1:
printf("ERROR:Creat pipe fail!\n");
exit(1);
break;
case 0:
switch(pid=fork())
{
case -1:
printf("ERROR:Creat pipe fail!\n");
exit(1);
case 0:
close(fd[1]);
for(i=0;i<3;i++)
{
read(fd[0],buf[i],35);
printf("%s\n",buf[i]);
sleep(1);
}
break;
default :
close(fd[0]);
for(i=0;i<3;i++)
{
write(fd[1],context[i],strlen(context[i]));
sleep(1);
}
wait(NULL);
break;
}
break;
}
}
4、 利用Linux/UNIX的软中断信号,编写一段C语言程序完成:显示数字1到100,在程序运行中如果捕获到一个SIGINT信号,则转去执行一段显示当前系统时间的程序。在编程中要考虑到信号被复位的情况,使程序能够实现多次被打断却多次的恢复执行。
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#include <stdlib.h>
void main()
{
void catchint(int signo);
int i;
signal(SIGINT,catchint);
for(i=1;i<101;i++)
{
printf("%d\n",i);
sleep(1);
}
printf("Exiting.\n");
exit(0);
}
void catchint(int signo)
{
struct tm *prt;
time_t it;
it=time(NULL);
prt=localtime(&it);
printf("%4d年%2d月%2d日 %2d:%2d:%d\n",prt->tm_year+1900,prt->tm_mon+1,prt->tm_mday,prt->tm_hour,prt->tm_min,prt->tm_sec);
}