Chinaunix首页 | 论坛 | 博客
  • 博客访问: 916460
  • 博文数量: 299
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2493
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-21 10:07
个人简介

Linux后台服务器编程。

文章分类

全部博文(299)

文章存档

2015年(2)

2014年(297)

分类: LINUX

2014-07-08 11:55:19

(1)fork和vfork
之前用过fork来创建子进程,知道可以根据返回值来区分父子进程,对于父进程来说,fork的返回值是子进程ID,对于子进程来说返回PID为0.关于这一点,vfork函数与fork函数是相同的。而fork与vfork的区别在于在哪呢?
*********************************************************************************
用fork创建的子进程会复制父进程的资源,而用vfork创建的子进程会与父进程共享地址空间。
*********************************************************************************
 
下面用函数的执行结果说明一下:
 
#include
#include
#include
int g_var = 0;
int main (void)
{
 int var = 1;
 pid_t pid;
 printf("Process ID: %ld\n",(long)getpid());
 printf("Before execute fork system call, g_val = %d,var = %d.\n",g_var,var);
 if((pid = fork())<0)
 {
  printf("Creat a new process failed.\n");
  return 1;
 }
 else if(pid==0)
 {
  g_var++;
  var++;
  printf("Process ID: %ld,g_var = %d,var =%d.\n",(long)getpid(),g_var,var);
  _exit(0);
 }
 printf("Process ID: %ld,g_var = %d,var =%d.\n",(long)getpid(),g_var,var);
 return 0;
}
修改以上代码,分别使用fork和vfork,执行结果如下:
--->使用fork
 gcc -o syst systemcall.c


 ./syst
Process ID: 6006
Before execute fork system call, g_val = 0,var = 1.
Process ID: 6007,g_var = 1,var =2.
Process ID: 6006,g_var = 0,var =1.

--->使用vfork

 gcc -o syst systemcall.c
 ./syst
Process ID: 5990
Before execute vfork system call, g_val = 0,var = 1.
Process ID: 5991,g_var = 1,var =2.
Process ID: 5990,g_var = 1,var =2.



以上结果可以证明:用fork函数创建子进程,子进程中修改变量不会影响父进程中变量的取值;用vfork函数创建子进程,子进程修改变量会导致父进程中对应变量值的改变。
*********************************************************************************
使用fork创建子进程往往不是为了获得完全一样的进程,而是通过exec来执行其他可执行程序,所以完全的复制有些多余,存在一定程度的资源消耗,vfork的出现促进了fork机制的改变,目前linux对fork系统调用的实现采用了写时复制(copy-on-write COW)的方法,只有子进程对内存数据进行写操作时,才会进行资源的复制。COW机制使vfork几乎没有了价值,而且子进程对内存的修改会影响父进程,需要特别注意。
**********************************************************************************
 
(2)extc函数族
在子进程中用exec执行其他的可执行程序,可以对进程中的代码段、数据段、堆栈段进行替换。主要几个函数有execl,execlp,execle,execv,execve,execvp(函数定义略)等。
 
exec后面为l,表示该函数可以使用可变参数(个数可变);包含v字符,表示支持使用参数列表;包含p,表示如果给出的程序没有给出所在路径,系统会自动搜索PATH路径(不包含p的必须给出文件所在完整路径)。
 
下面函数示范了execlp和execvp的使用,后者明显具备更大的灵活性。
#include
#include
int main (int argc,char* argv[])
{
 
 if(argc <2)
 {
  printf("Usage: %s path.\n",argv[0]);
  return 1;
 }
 execlp("/bin/ls","ls",argv[1],(char*)NULL); //支持变长参数,以NULL结尾
 return 0;
}
执行结果:
--->execlp()

 gcc -o syst2 systemcall2.c
 ./syst2
Usage: ./syst2 path.
 ./syst2 /home/gaolu
commen files        music
data.dat~        picture
desktop         process.c~
document        program~
etcnetworkinterface       syst
Examples        syst2
fcitx-3.4.2        systemcall2.c
fcitx-install        systemcall2.c~
file.c~         systemcall.c~
fileopera~        test.c~
file_operate.c ~       test.dat~
fork_file.c~        test_folder
gao.lu.c~        test_program
ls~         test_program (copy)
LumaQQ         uid.c~
lumaqq_2005-linux_gtk2_x86_with_jre.tar.gz  uidprint.c~
mnt         video
module


--->execvp()
#include
#include
int main (int argc,char* argv[])
{
 
 if(argc <2)
 {
  printf("Usage: %s arg list 1 2 3...\n",argv[0]);
  return 1;
 }
 
 execvp(argv[1],&argv[1]);
 return 0;
}
执行结果:
 gcc -o syst3 systemcall2.c
 ./syst3
Usage: ./syst3 arg list 1 2 3...


 ./syst3 ls /home/gaolu
commen files        music
data.dat~        picture
desktop         process.c~
document        program~
etcnetworkinterface       syst
Examples        syst2
fcitx-3.4.2        syst3
fcitx-install        systemcall2.c
file.c~         systemcall2.c~
fileopera~        systemcall.c~
file_operate.c ~       test.c~
fork_file.c~        test.dat~
gao.lu.c~        test_folder
ls~         test_program
LumaQQ         test_program (copy)
lumaqq_2005-linux_gtk2_x86_with_jre.tar.gz  uid.c~
mnt         uidprint.c~
module         video
 
(3)exit和_exit
可以将两者用在main函数中替代return,区别是exit和_exit不考虑返回值类型。
exit和_exit之间的区别在于:
*****************************************************************************************
[1] exit是在ANSIC中说明,_exit是在POSIX中说明。
[2] exit终止调用进程,退出之前关闭所有文件,清空标准输入输出缓冲区,并执行在atexit中注册的回调函数;_exit终止调用进程,但是不关闭文件,不清除标准输入输出缓冲区,也不调用回调函数。
因此vfork()创建的子进程可以调用_exit退出,但是不要调用exit()退出。
*****************************************************************************************
举例如下:
#include
#include
#include
void do_at_exit(void)
{
 printf("You can see the output when the program teminates.\n");
}
int main ()
{
 int flag = 0;
 
 flag = atexit(do_at_exit);
 if(flag != 0)
 {
  printf("Can't set exit function.\n");
  return EXIT_FAILURE;
 }
 
 exit(EXIT_SUCCESS);
}
执行结果:


 gcc -o syst4 systemcall2.c

 ./syst4
You can see the output when the program teminates.   //执行了注册的回调函数

将函数修改为_exit()以后执行结果如下:
#include
#include
#include
void do_at_exit(void)
{
 printf("You can see the output when the program teminates.\n");
}
int main ()
{
 int flag = 0;
 
 flag = atexit(do_at_exit);
 if(flag != 0)
 {
  printf("Can't set exit function.\n");
  return EXIT_FAILURE;
 }
 
 _exit(EXIT_SUCCESS);
}
 gcc -o syst5 systemcall2.c
 ./syst5      //返回shell之前不会执行do_at_exit()

阅读(1200) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~