linux fork函数与vfork函数,exit,_exit区别
man vfork:
NAME
vfork - create a child process and block parent
SYNOPSIS
#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);
DESCRIPTION
Standard description
(From POSIX.1) The vfork() function has the same effect as fork(2), except that the behav‐
ior is undefined if the process created by vfork() either modifies any data other than a
variable of type pid_t used to store the return value from vfork(), or returns from the
function in which vfork() was called, or calls any other function before successfully
calling _exit(2) or one of the exec(3) family of functions.
Linux description
vfork(), just like fork(2), creates a child process of the calling process. For details
and return value and errors, see fork(2).
vfork() is a special case of clone(2). It is used to create new processes without copying
the page tables of the parent process. It may be useful in performance-sensitive applica‐
tions where a child is created which then immediately issues an execve(2).
vfork() differs from fork(2) in that the calling thread is suspended until the child ter‐
minates (either normally, by calling _exit(2), or abnormally, after delivery of a fatal
signal), or it makes a call to execve(2). Until that point, the child shares all memory
with its parent, including the stack. The child must not return from the current function
or call exit(3), but may call _exit(2).
As with fork(2), the child process created by vfork() inherits copies of various of the
caller's process attributes (e.g., file descriptors, signal dispositions, and current
working directory); the vfork() call differs only in the treatment of the virtual address
space, as described above.
Signals sent to the parent arrive after the child releases the parent's memory (i.e.,
after the child terminates or calls execve(2)).
创建一个新进程的方法只有由某个已存在的进程调用fork()或vfork(),当然某些进程如init等是作为系统启动的一部风而被内核创建的。
一、fork
1. 调用方法
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
正确返回:在父进程中返回子进程的进程号,在子进程中返回0
错误返回:-1
子进程是父进程的一个拷贝。即,子进程从父进程得到了数据段和堆栈段的拷贝,这些需要分配新的内存;而对于只读的代码段,通常使用共享内存的方式访问。fork返回后,子进程和父进程都从调用fork函数返回处开始执行。
父进程与子进程的不同之处在于:fork的返回值不同——父进程中的返回值为子进程的进程号,而子进程为0
2. fork函数调用的用途
⑴ 一个进程希望复制自身,从而父子进程能同时执行不同段的代码。
⑵ 进程想执行另外一个程序
二、vfork
1. 调用方法
与fork函数完全相同
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
正确返回:在父进程中返回子进程的进程号,在子进程中返回0
错误返回:-1
2. vfork函数调用的用途
用vfork创建的进程主要目的是用exec函数执行另外的程序,与fork的第二个用途相同
三、fork与vfork的区别
1. fork要拷贝父进程的数据段;而vfork则不需要完全拷贝父进程的数据段,在子进程没有调用exec和exit之前,子进程与父进程共享数据段
2. fork不对父子进程的执行次序进行任何限制;而在vfork调用中,子进程先运行,父进程挂起,直到子进程调用了exec或exit之后,父子进程的执行次序才不再有限制
四、结束子进程
结束子进程不用exit(0),而使用_exit(0)。这是因为_exit(0)在结束进程时,不对标准I/O流进行任何操作。而exit(0)则会关闭进程的所有标准I/O流。
由于子进程与父进程的运行是无关的,父进程可先于子进程运行,子进程也可先于父进程运行,所以下段程序可以有两种运行结果。
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int global=;
int main()
{
pid_t pid;
int vari=;
printf("before fork\n");
if((pid=fork())==)
{
global++;
vari--;
printf("child changed\n");
}
else
printf("parent did nog changed\n"); printf("global=%d,vari=%d\n",global,vari);
}
root@iZ23onhpqvwZ:~/ms/linux/unp/unpMy/tcpcliserv# ./fork1
before fork
parent did nog changed
global=4,vari=5
root@iZ23onhpqvwZ:~/ms/linux/unp/unpMy/tcpcliserv# child changed
global=5,vari=4
root@happy src]# ./a.out
before fork
Child changed
globa = 5 vari = 4
Parent did not changde
globa = 4 vari = 5
vfork创建新进程的主要目的在于用exec函数执行另外的程序,实际上,在没调用exec或exit之前子进程的运行中是与父进程共享数据段的。在vfork调用中,子进程先运行,父进程挂起,直到子进程调用exec或exit,在这以后,父子进程的执行顺序不再有限制。
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int global=;
int main()
{
pid_t pid;
int vari=;
printf("before fork\n");
if((pid=vfork())==)
{
global++;
vari--;
printf("child changed\n");
_exit();
}
else
printf("parent did nog changed\n"); printf("global=%d,vari=%d\n",global,vari);
exit();
}
root@iZ23onhpqvwZ:~/ms/linux/unp/unpMy/tcpcliserv# ./fork2
before fork
child changed
parent did nog changed
global=5,vari=4。
(从这里可以看出共享了数据段的。)
参考:http://blog.csdn.net/lingdxuyan/article/details/4996471
vfork
保证子进程先运行,在她调用
exec
或
exit
之后父进程才可能被调度运行。如果在
调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。
#include<unistd.h>
#include<stdio.h>
int main()
{
pid_t pid;
int count=; pid=vfork();
count++;
printf("count=%d\n",count);
//return 0;没有return 0
}
ubuntu输出:
root@iZ23onhpqvwZ:~/ms/linux/unp/unpMy/tcpcliserv# ./vfork1
count=1
count=2
vfork1: cxa_atexit.c:100: __new_exitfn: Assertion `l != ((void *)0)' failed.
Aborted
有return 0,输出:
count=1
count=2
count=1
count=2
count=1
count=2
........................
如果没有_exit(0)的话,子进程没有调用exec或exit,所以父进程是不可能执行的,在子进程调用exec或exit之后父进程才可能被调度运行。 所以我们加上_exit(0);使得子进程退出,父进程执行,这样else后的语句就会被父进程执行,又因在子进程调用exec或exit之前与父进程数据是共享的,所以子进程退出后把父进程的数据段count改成1了,子进程退出后,父进程又执行,最终就将count变成了2,
改成:
pid_t pid;
int count=; pid=vfork();
if(pid==)
{
count++;
_exit();
}
else
{
count++;
}
printf("count=%d\n",count);
return ;
网上抄的一段,可以再理解理解:
为什么会有vfork,因为以前的fork很傻,当它创建一个子进程时,将会创建一个新的地址空间,并且拷贝父进程的资源,而往往在子进程中会执行exec调用,这样,前面的拷贝工作就是白费力气了,这种情况下,聪明的人就想出了vfork,它产生的子进程刚开始暂时与父进程共享地址空间(其实就是线程的概念了),因为这时候子进程在父进程的地址空间中运行,所以子进程不能进行写操作,并且在儿子“ 霸占”着老子的房子时候,要委屈老子一下了,让他在外面歇着(阻塞),一旦儿子执行了exec或者exit后,相当于儿子买了自己的房子了,这时候就相当于分家了。
linux c 下exit(0);与_exit(0);的区别
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
pid_t pid;
if((pid=fork())==-)
{
printf("error");
}
else if(pid==)
{
printf("ok\n");
exit();
}
else
{
printf("parent process,output begin\n");
printf("hello word");
_exit();
}
}
调试后你会发现没有
hello word
exit是退出去先把内存中的数据输出到文件中,而_exit 这个直接退出,消除内存中的数据;
printf是标准行输出,遇到“\n”或者是写入的内存满了才会标准输出;
我们可以尝试在hello word 中加入很多i,假设输入2000个吧(关于行输出自行google),再次调试发现,会有 hello 等字符,这就是溢出了。
回到前面,为什么开始没有hello,虽然hello word 在_exit前,但是你查看汇编会发现,他只是讲数据存在内存中。没有讲数据真正输出。当我们把_exit去掉 hello word就能显示了。为什么呢?这个就是编译器自己加的了。
从图中可以看出,_exit 函数的作用是:直接使进程停止运行,清除其使用的内存空间,并清除其在内核的各种数据结构;exit 函数则在这些基础上做了一些小动作,在执行退出之前还加了若干道工序。exit() 函数与 _exit() 函数的最大区别在于exit()函数在调用exit 系统调用前要检查文件的打开情况,把文件缓冲区中的内容写回文件。也就是图中的“清理I/O缓冲”。
所需头文件: exit: #include<stdlib.h>
_exit: #include<unistd.h>
函数原型:exit: void exit(int status)
_exit: void _exit(int status)
函数传入值:status 是一个整型的参数,可以利用这个参数传递进程结束时的状态。一般来说,0表示正常结束;其他的数值表示出现了错误,进程非正常结束。在实际编程时,父进程可以利用wait 系统调用接收子进程的返回值,从而针对不同的情况进行不同的处理
参考:http://blog.csdn.net/lwj103862095/article/details/8640037
atexit()函数
atexit可以注册终止处理程序,ANSI C规定最多可以注册32个终止处理程序。
终止处理程序的调用与注册次序相反
#include <stdlib.h>
int atexit(void (*function)(void));
#include <stdio.h>
#include <stdlib.h>
void exit_fn1(void)
{
printf("Exit function #1 called\n");
}
void exit_fn2(void)
{
printf("Exit function #2 called\n");
} int main()
{
atexit(exit_fn1);
atexit(exit_fn2); return ;
}
linux fork函数与vfork函数,exit,_exit区别的更多相关文章
- fork 函数 和vfork 函数的区别
问题描述: fork 函数 和vfork 函数的区别 问题解决: fork函数使用: 注: 以上printf 属于标准IO库带缓冲,如果标准输出链接到终端设备,则它是行 ...
- linux fork函数与vfork函数
一.fork1. 调用方法#include <sys/types.h>#include <unistd.h> pid_t fork(void);正确返回:在父进程中返回子进程的 ...
- fork函数和vfork函数的区别--19
fork()与vfock()都是创建一个进程,那他们有什么区别呢?总结有以下三点区别: 1. fork ():子进程拷贝父进程的数据段,代码段 vfork ( ):子进程与父进程共享数据段 ...
- linux系统编程之进程(四):进程退出exit,_exit区别即atexit函数(转载)
一,进程终止有5种方式: 正常退出: 从main函数返回 调用exit 调用_exit 异常退出: 调用abort 由信号终止 二,exit和_exit区别: 关于_exit(): #include ...
- Linux学习之“vfork函数”
为什么使用vfork()? 希望父子进程执行不同的代码.例如: 网络服务程序中,父进程等待客户端的服务请求,当请求达到时,父进程调用fork,使子进程处理该次请求,而父进程继续等待下一个服务请求到达. ...
- [转帖]Linux下fork函数及pthread函数的总结
Linux下fork函数及pthread函数的总结 https://blog.csdn.net/wangdd_199326/article/details/76180514 fork Linux多进程 ...
- 转:Linux fork与vfork的深入分析
源地址:http://linux.chinaitlab.com/c/831529.html 一)fork的概述 .操作系统对进程的管理,是通过进程表完成的.进程表中的每一个表项,记录的是当前操作系统中 ...
- 进程控制之vfork函数
vfork函数的调用序列和返回值与fork相同,但两者的语义不同. vfork用于创建一个新进程,而新进程的目的是exec一个新程序.vfork和fork一样都创建一个子进程,但是它并不将父进程的地址 ...
- (转)linux下execl和system函数
linux下,system函数和execl函数都是用于执行一条系统命令.今天仔细看了system函数的实现,想找出和execl函数的差别. 这里先进行一些背景知识补充: fork(创建一个新的进程): ...
随机推荐
- 【Evaluate Reverse Polish Notation】cpp
题目: Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are + ...
- 《Soft Skill》一书中的好句子
The biggest mistake that you can make is to believe that you are working for somebody else. Job secu ...
- ubuntu重置root密码
from: http://mmicky.blog.163.com/blog/static/150290154201398113034698/ 使用ubuntu的时候忘记了root密码该如何重置?我使用 ...
- 802.11 wireless 三
802.11 wireless 3watts,milliwatts,and Decibels瓦特(功率单位)的定义是1焦耳/秒微波炉1000瓦特,手机100-200毫瓦 decibels(分贝:比较能 ...
- RAID磁盘阵列学习笔记
RAID是“Redundant Array of Independent Disk”的缩写,中文意思是独立冗余磁盘阵列.简单地解释,就是将N台硬盘通过RAID Controller(分Hardware ...
- zero to one:创业秘籍并不存在,因为任何创新都是新颖独特的,任何权威都不可能具体规定如何创新
彼得·蒂尔(Peter Thiel)的新作<从0到1>从预售开始就占据美国亚马逊排行榜第一名的位置,被一批创业家和企业家评为“迄今为止最好的商业书”.这是一本关于如何创建创新公司的书,主要 ...
- ibatis的iterate使用
Iterate:这属性遍历整个集合,并为 List 集合中的元素重复元素体的内容. Iterate 的属性: prepend - 可被覆盖的 SQL 语句组成部分,添加在语句的前面(可选 ...
- python模拟shell
import fileinput import readline raw_input(xxx) exec filepinput.input
- sqlite3中的数据类型
大多数的数据库引擎(到现在据我们所知的除了sqlite的每个sql数据库引擎)都使用静态的.刚性的类型,使用静态类型,数据的类型就由它的容器决定,这个容器是这个指被存放的特定列. Sqlite使用一个 ...
- POJ1474 Video Surveillance(半平面交)
求多边形核的存在性,过了这题但是过不了另一题的,不知道是模板的问题还是什么,但是这个模板还是可以过绝大部分的题的... #pragma warning(disable:4996) #include & ...