fork和vfork的区别(待细看)

fork和vfork的区别(待细看)
fork和vfork的区别(待细看)

NO2、fork和vfork的区别(待细看)

fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性,但是二者之间的通讯需要通过专门的通讯机制,如:pipe,popen&pclose、协同进程、fifo,System V IPC(消息队列、信号量和共享内存)机制等,另外通过fork创建子进程系统开销很大,需要将上面描述的每种资源都复制一个副本。这样看来,fork是一个开销十分大的系统调用,这些开销并不是所有的情况下都是必须的,比如某进程fork出一个子进程后,其子进程仅仅是为了调用exec执行另一个执行文件,那么在fork过程中对于虚存空间的复制将是一个多余的过程(由于Linux中是采取了copy-on-write技术,所以这一步骤的所做的工作只是虚存管理部分的复制以及页表的创建,而并没有包括物理也面的拷贝);

vfork系统调用不同于fork,用vfork创建的子进程共享地址空间,也就是说子进程完全运行在父进程的地址空间上,子进程对虚拟地址空间任何数据的修改同样为父进程所见。但是用vfork创建子进程后,父进程会被阻塞直到子进程调用exec或exit。这样的好处是在子进程被创建后仅仅是为了调用exec执行另一个程序时,因为它就不会对父进程的地址空间有任何引用,所以对地址空间的复制是多余的,通过vfork可以减少不必要的开销。

按指定条件创建子进程。Linux内核在2.0.x版本就已经实现了轻量进程,应用程序可以通过一个统一的clone()系统调用接口,用不同的参数指定创建轻量进程还是普通进程。在内核中,clone()调用经过参数传递和解释后会调用do_fork(),这个核内函数同时也是fork()、vfork()系统调用的最终实现

在fork之后,子进程和父进程都会继续执行fork调用之后的指令。子进程是父进程的副本。它将获得父进程的数据空间,堆和栈的副本,这些都是副本,父子进程并不共享这部分的内存。也就是说,子进程对父进程中的同名变量进行修改并不会影响其在父进程中的值。但是父子进程又共享一些东西,简单说来就是程序的正文段。正文段存放着由cpu 执行的机器指令,通常是read-only的。

由于在fork之后我们常常都是跟个exec在后面,所以为了提高效率,很多的实现并不完全复制数据段和堆、栈,而是采用写时复制,有点类似于某些cache与内存数据的同步方法。

另一种提高效率的方法就是使用vfork,vfork最早起源于2.9BSD,它与fork的不同就在于它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec。vfork出来的子进程是在父进程的空间中运行的,它的存在就是为了exec调用,所以它不需要复制这些东西,因为复制了也没有用。如果这时子进程修改了某个变量,这将影响到父进程。

vfork与fork的另一区别是:vfork保证子进程先运行,在它调用exec或exit后父进程才可能调度运行。而fork的父子进程运行顺序是不定的,它取决于内核的调度算法。

所以,fork的时候,程序代码被复用了——我指的程序代码就是由cpu执行的机器指令部分,这与有多少个进程在运行无关,即使是频繁执行的程序在存储器中也只需一个副本,而且它在执行期可能是read-only的。当然,如果你exec 了,那就是另一码事了。另外,父进程中的数据空间和堆、栈可能会产生副本,具体情况要看你使用的是vfork还是fork。fork会产生副本,而vfork则共享这部分内存。

NO3、spinlock,mutex,semaphore,vitical section的作用与区别?(待详细研究)

Critical Section,其他都能用于进程间同步,临界段只能用于进程内部,是轻量级同步对象。

spinlock是自旋锁,用于多cpu的情况

mutex就是普通的跨进程同步对象

semaphore用于对资源数的控制

NO4、strncpy,栈溢出问题,如何规避和解决?

Strcpy和Strncpy的区别- -

第一种情况:

char* p="how are you ?";

char name[20]="ABCDEFGHIJKLMNOPQRS";

strcpy(name,p); //name改变为"how are you ? OPQRS " ====>错误!

strncpy(name,p,sizeof(name)) //name改变为"how are you ? " ====>正确!

第二种情况:

char* p="how are you ?";

char name[20];

strcpy(name,p); //name改变为"how are you ? 未知字符" ====>错误!

name[sizeof(name)-1]='\0' //和上一步组合,得到正确的结果!

strncpy(name,p,sizeof(name)); //name改变为"how are you ? " ====>正确!

第三种情况:

char* p="how are you ?";

char name[10];

strcpy(name,p); //name改变为"how are yo" ====>无结束符'\0',错误!

name[sizeof(name)-1]='\0' //和上一步组合,弥补结果。但要注意,字符传递错误!strncpy(name,p,sizeof(name)); //和单纯的一步strcpy结果一样!

总结:strcpy

如果源长>目标长,则将源长中等于目标长的字符拷贝到目标字符串

如果源长<目标长,则源长全部拷贝到目标字符串,不包括'\0'

strncpy

如果目标长>指定长>源长,则将源长全部拷贝到目标长,自动加上'\0'

如果指定长<源长,则将源长中按指定长度拷贝到目标字符串,不包括'\0'

如果指定长>目标长,error happen!

strncpy(sptsf_cert.peer_ditm_no,clr_total.payint_acc+7,8) //从第8位后8位拷贝strncpy(sptsf_cert.recv_inst,clr_total.payint_acc,4);//拷贝前四位

总结:strcpy

如果源长>目标长,则将源长中等于目标长的字符拷贝到目标字符串

如果源长<目标长,则源长全部拷贝到目标字符串,不包括'\0'

strncpy

如果目标长>指定长>源长,则将源长全部拷贝到目标长,自动加上'\0'

如果指定长<源长,则将源长中按指定长度拷贝到目标字符串,不包括'\0'

如果指定长>目标长,error happen!

strncpy(sptsf_cert.peer_ditm_no,clr_total.payint_acc+7,8) //从第8位后8位拷贝strncpy(sptsf_cert.recv_inst,clr_total.payint_acc,4);//拷贝前四位

NO5、release版本,可执行程序文件过大,可能是什么原因?(有待后序整理)

不会,请赐教

NO6、如何减少和避免锁的使用?

NO7、c++赋值需要注意什么?

NO8、软件开发分为几个过程,每个过程如何保证质量?

fork函数和子进程

Fork函数 函数pid_t fork(void) 正确返回:在父进程中返回子进程的进程号,在子进程中返回0 错误返回:-1 子进程是父进程的一个拷贝。即,子进程从父进程得到了数据段和堆栈段的拷贝,这些需要分配新的内存;而对于只读的代码段,通常使用共享内存的方式访问。fork返回后,子进程和父进程都从调用fork函数的下一条语句开始执行。父进程与子进程的不同之处在于:fork的返回值不同——父进程中的返回值为子进程的进程号,而子进程为0。 以下是fork的两个示例程序: //fork.c #include #include void main () { int pid; //printf("Process [%d] begin",getpid()); //print twice printf("Process [%d] begin\n",getpid()); //print once //由于fork时pc等值的拷贝,子进程只会从fork处开始执行 pid = fork(); if (pid < 0) printf("error in fork!"); else if (pid == 0) printf("I'm child process, my pid is %d\n", getpid()); else printf("I'm parent process, my pid is %d\n", getpid()); printf("Process [%d] end\n",getpid()); return; } 输出结果: 使用printf("Process [%d] begin\n",getpid())时 Process [11155] begin I'm parent process, my pid is 11155

操作系统实验2课前说明-fork函数

关于fork函数的多进程编程研究 首先我们来看一下多进程的使用,我们简单的使用fork函数来实现。第一步:我们man fork一下,发现它所依赖的头文件是:sys/types.h 和unistd.h好吧,于是我们开始来使用它。 代码一: #include #include #include main() {pid_t pid; //pid_t 类型实际上就是int型 pid = fork(); if(pid < 0) printf("erro \n"); else if(pid == 0){ printf("child \n"); } else{ printf("parnts \n"); }} 这个就是最简单的fork使用了,编译一下,输出: [xdyang@SEP4020 learning]$ ./fork child

parnts 好了,大家就要开始问了,为什么会这样?同样一个if的判断语句,为什么会要进去两次?其实很简单,这个我们今天这段代码所要实现的功能:多进程。当一个进程调用fork函数后,就会创建一个子进程,子进程会拷贝(见附录二)父进程的代码段,但是拥有自己的数据段。也就是说,其实我们调用了fork函数后,相当于把这个函数代码复制了一遍,也就是产生了类似下面这样的代码: #include #include #include main(){ //进程一 pid_t pid; pid = fork(); if(pid < 0) printf("erro \n"); else if(pid == 0){ printf("child \n"); } else{ printf("parnts \n"); } //进程二 if(pid < 0) printf("erro \n"); else if(pid == 0){ printf("child \n"); } else{ printf("parnts \n"); } }

fork函数实验总结

针对fork函数难以理解,根据网上的解释,参考他人代码,做了如下实验,并附以实验分析 2 #include 3 #include 4 #include 5 #include 6 #include 7 8 int main () 9 { 10 pid_t pc,pr; 11 pc=fork(); (gdb) 12 13 if (pc<0) 14 { 15 printf("error fork.\n"); 16 17 } 18 else if (pc==0) 19 { 20 printf("this is pc=%d\n",getpid()); 21 sleep(5); (gdb) 22 printf("5 s over\n"); 23 //exit(0); 24 } 25 pr=fork(); 26 if (pr==0) 27 { 28 printf("this is pr =%d\n",getpid()); 29 } 30 31 else if (pr>0&&pc>0) (gdb) 32 printf("this is main =%d",getpid()); 33 34 35 36 37 38 } (gdb) b 12

Breakpoint 1 at 0x804849d: file /home/lsp/fork3.c, line 12. (gdb) b 19 Breakpoint 2 at 0x80484b7: file /home/lsp/fork3.c, line 19. (gdb) b 24 Breakpoint 3 at 0x80484e4: file /home/lsp/fork3.c, line 24. (gdb) b 26 Breakpoint 4 at 0x80484ec: file /home/lsp/fork3.c, line 26. (gdb) run Starting program: /home/lsp/fork3 Detaching after fork from child process 13200. ---说明pc=fork()函数已经建立子进程 this is pc=13200 Breakpoint 1, main () at /home/lsp/fork3.c:13 13 if (pc<0) (gdb) 5 s over this is pr =13201 --说明pc=fork()进程13200启动了新的子进程pr 其pid=13201 next Breakpoint 3, main () at /home/lsp/fork3.c:25 25 pr=fork(); --父进程停在pr=fork()处, (gdb) next Detaching after fork from child process 13254. this is pr =13254 --此处pr的pid=13254 与上一个pr=13201不同,这说明此处的pr是由main创建的 Breakpoint 4, main () at /home/lsp/fork3.c:26 26 if (pr==0) (gdb) next 31 else if (pr>0&&pc>0) (gdb) next 32 printf("this is main =%d",getpid()); (gdb) next 38 } (gdb) next 0x00a6d5d6 in __libc_start_main () from /lib/libc.so.6 (gdb) next Single stepping until exit from function __libc_start_main, which has no line number information. this is main =13199 ---main函数退出,器pid=13199 Program exited with code 023. (gdb)

A和An的用法

A和An的意思其实是一样的,都表示一个或单数的意思。当修饰的名字开头是元音(特别注意:是发音是元音而不是字母是元音字母啊)时,用an,例如an interesting book,而a则用于辅音开头的单词,例如a happy ending 名词的第一个发音为元音音标时,用an eg: an eye, an ear 名词的第一个发音为辅音音标时,用a eg: a hand 英语字母u前面的不定冠词a,an 的确定让学生头痛,怎么掌握呢?很简单,U 发字母表音的单词前是a,不发字母表音的单词前是an: a university 一所大学 a useful book 一本有用的书 an umbrella 一把雨伞 an underground train 一部地铁列车 冠词一般位于所限定的名词前,用来署名名词所指的人或事物。冠词有不定冠词和定冠词两种。不定冠词有两个形式,即a和an。a用在以辅音音素开头的词前,如a book; an用在以元音音素开头的字母前,如an apple. a或an与可数名词单数连用,泛指某类人或某物中的一个。the既可以用在可数名词前,也可以用在不可数名词前,表示某个或某些特定的人或事物,也可以指上文提到过的人或事物。 the/an/a用法及区别: 冠词在英文中属于虚词,在句子里主要是对名词起限定作用。这类词的数量很小,但是其活动性却很大,很大。在英文中,a / an并不等于one 。 例:He only has one dictionary.他只有一本词典。(正确) He only has a dictionary.他只有一本词典。(错误) One minute is enough for me to do it . 我做这件事一分钟足够了。(正确) A minute is enough for me to do it . 我做这件事一分钟足够了(错误) 1)不定冠词在句子中最大的语法功能是:用在可数名词的单数形式前表示泛指--表明一类人或事物区别于它类。 例:I am a Chinese. 我是(一个)中国人。 This is a book. 这是(一本)书。 2)为了读音的方便,在以元音音素开头的可数 名词的单数名词前用an而不用a。当我们使用an时,条件有三:①这个名词的读音必须是以元音音素开头--即它的音标的第一个音素是元音,而不是说它是以元音字母开头。②它必须是个可数名词。③它还必须是个单数名词。我们常常见到这类用法: a university 一所大学an hour 一个小时 an orange 一只桔子an engineer 一位工程师 an ordinary man一个普通人 an honest person一位诚实的人

进程创建之fork系统调用

4 进程创建 (1) 4.1 实验内容及要求 (1) 4.2 实验目的 (1) 4.3 实验环境 (1) 4.4 实验思路 (1) 4.5 实验代码 (2) 4.6 运行结果 (3) 4.7 实验心得 (3) 4 进程创建 4.1 实验内容及要求 利用fork()系统调用创建进程。要求如下: 编制一段程序,使用系统调用fork( )创建两个子进程,这样在此程序运行时,在系统中就有一个父进程和两个子进程在活动。每一个进程在屏幕上显示一个字符,其中父进程显示字符A,子进程分别显示字符 B和字符C。试观察、记录并分析屏幕上进程调度的情况。 4.2 实验目的 了解进程的创建过程,进一步理解进程的概念,明确进程和程序的区别。 4.3 实验环境 Ubuntu 18.04.1 LTS 64位,编译器gcc 7.3.0 (Ubuntu 7.3.0-16ubuntu3) 4.4 实验思路 (1)可用fork()系统调用来创建一个新进程。 系统调用格式:pid=fork() fork()返回值意义如下: =0:若返回值为0,表示当前进程是子进程。 >0:若返回值大于0,表示当前进程是父进程,返回值为子进程的pid值。

<0:若返回值小于0,表示进程创建失败。 如果fork()调用成功,它向父进程返回子进程的pid,并向子进程返回0,即fork()被调用了一次,但返回了两次。此时OS在内存中建立一个新进程,所建的新进程是调用fork()父进程的副本,称为子进程。子进程继承了父进程的许多特性,并具有与父进程完全相同的用户级上下文。父进程与子进程并发执行。 (2)编译和执行的方法: 编译:在shell提示符下输入gcc 源文件名 -o 可执行文件名 运行:在shell提示符下输入 ./可执行文件名 4.5 实验代码 #include #include #include int main(void) { pid_t p1=fork();pid_t p2=fork(); //迭代调用fork(),创建三个新进程printf("this is parent, pid = %d\n", getpid()); //父进程 if(p1<0||p2<0){ //fork()失败 printf("fork failed with p1=%d, p2=%d\n", p1, p2); exit(1); }if(p1==0&&p2==0){ //子进程B创建的子进程D,即孙进程 printf("D in grandson Damson, pid = %d\n", getpid()); }if(p1==0&&p2>0){ //父进程创建的子进程B printf("B in child Blueberry, pid = %d\n", getpid()); }if(p1>0&&p2==0){ //父进程创建的子进程C printf("C in child Carambola, pid = %d\n", getpid()); }if(p1>0&&p2>0){ //父进程 printf("A in parent Apple, pid = %d\n", getpid()); }return 0; }

Linux的fork、exec、wait函数的分析

Linux 的fork 、exec 、wait 函数分析 I 数学与计算机学院 课程设计说明书 课 程 名 称: 操作系统原理-课程设计 课 程 代 码: 8404061 题 目: Linux 的fork 、exec 、wait 函数的分析 年级/专业/班: 学 生 姓 名: 学 号: 3 开 始 时 间: 2010 年 12 月 12 日 完 成 时 间: 2011 年 01 月 09 日 课程设计成绩: 指导教师签名: 年 月 日

Linux 的fork 、exec 、wait 函数分析 II 目 录 1 引 言 ................................................................. 1 1.1 问题的提出 ...................................................................................................................... 1 1.2国内外研究的现状 ........................................................................................................... 1 1.3任务与分析 ....................................................................................................................... 1 2代码分析结果 ............................................................ 2 2.1 数据结构 ......................................................................................................................... 2 2.1.1 struct task_struct ............................................................................................. 2 2.1.2 task ......................................................................................................................... 3 2.1.3 tarray_freelist ................................................................................................... 3 2.1.4 struct--linux_binprm ......................................................................................... 3 2.1.5进程状态 .................................................................................................................. 4 2.2常量和出错信息的意义 .................................................................................................. 4 2.3调用关系图 ...................................................................................................................... 4 2.4各模块/函数的功能及详细框图 .................................................................................... 5 2.4.1 do_fork 模块 .......................................................................................................... 5 2.4.2 get_pid 模块 .......................................................................................................... 8 2.4.3 do_execve 模块 ........................................................................................................ 10 3.4.4 do_exit 模块 ........................................................................................................ 14 3.4.5 sys_wait4模块 .................................................................................................. 18 3 总结与体会 ............................................................ 20 4 参考文献 .. (20)

fork函数

fork函数 在linux中,只有一个函数可以创建子进程:fork。 #include #include pid_t fork(void); 由f o r k创建的新进程被称为子进程(child process)。该函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是0,而父进程的返回值则是新子进程的进程I D。将子进程I D返回给父进程的理由是:因为一个进程的子进程可以多于一个,所以没有一个函数使一个进程可以获得其所有子进程的进程I D。f o r k使子进程得到返回值0的理由是:一个进程只会有一个父进程,所以子进程总是可以调用g e t p p i d以获得其父进程的进程I D (进程ID 0总是由交换进程使用,所以一个子进程的进程I D不可能为0 )。 子进程和父进程共享很多资源,除了打开文件之外,很多父进程的其他性质也由子进程继承: ? 实际用户I D、实际组I D、有效用户I D、有效组I D。 ? 添加组I D。 ? 进程组I D。 ? 对话期I D。 ? 控制终端。 ? 设置-用户- I D标志和设置-组- I D标志。 ? 当前工作目录。 ? 根目录。 ? 文件方式创建屏蔽字。 ? 信号屏蔽和排列。 ? 对任一打开文件描述符的在执行时关闭标志。 ? 环境。 ? 连接的共享存储段。 ? 资源限制。 父、子进程之间的区别是: ? fork的返回值。

? 进程I D。 ? 不同的父进程I D。 ? 子进程的t m s _ u t i m e , t m s _ s t i m e , t m s _ c u t i m e以及t m s _ u s t i m e设置为0。 ? 父进程设置的锁,子进程不继承。 ? 子进程的未决告警被清除。 ? 子进程的未决信号集设置为空集。 使f o r k失败的两个主要原因是:( a )系统中已经有了太多的进程(通常意味着某个方面出了问题),或者( b )该实际用户I D的进程总数超过了系统限制。回忆表2 - 7,其中C H I L D _ M A X规定了每个实际用户I D在任一时刻可具有的最大进程数。 f o r k有两种用法: (1) 一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在 网络服务进程中是常见的——父进程等待委托者的服务请求。当这种请求到达时,父进程调用f o r k,使子进程处理此请求。父进程则继续等待下一个服务请求。 (2) 一个进程要执行一个不同的程序。这对s h e l l是常见的情况。在这种情 况下,子进程在从f o r k返回后立即调用e x e c。 我们从一个例子程序中可以看到fork函数的作用,子进程与父进程之间的资源共享。

Linux C 中vfork和fork的区别

Linux C 中vfork和fork的区别 我们知道, fork会创建一个新的进程,这个新的进程是当前进程的子进程,区别在于, fork函数会复制父进程的一些资源,也就是,仅仅是复制的关系,而非共享。而vfork就不同了,利用vfork创建的子进程和父进程共享地址空间,下面,我们通过实际程序来看看: 1、fork函数的简单应用: #include #include #include int main() { int a = 0; pid_t pid; pid = fork(); if(pid < 0) { printf("error\n"); return -1; } else if(0 == pid) { printf("child\n"); printf("%d\n" a); } else { a = 1;

printf("parent\n"); printf("%d\n" a); } return 0; } 运行一下,结果为: parent 1 child 由此可见,父进程值的修改,不会影响到子进程,为什么呢?因为他们没有共享地址空间啊。 2、我们再看看vfork: #include #include #include int main() { int a = 0; pid_t pid; pid = vfork(); if(pid < 0) { printf("error\n"); return -1;

} else if(0 == pid) { a = 1; printf("child\n"); printf("%d\n" a); _exit(0); // 这个先不管它,以后再说 } else { printf("parent\n"); printf("%d\n" a); } return 0; } 结果为: child 1 parent 1 可见, vfork创建的子进程和父进程确实共享着内存空间呢。

fock()函数问题

#include #include #include int main() { pid_t pid1; pid_t pid2; pid1 = fork(); pid2 = fork(); printf("pid1:%d, pid2:%d\n", pid1, pid2); } 输出: pid1:3411, pid2:3412 pid1:0, pid2:3413 pid1:3411, pid2:0 pid1:0, pid2:0 1. 基础知识: 1)fork函数总是“调用一次,返回两次”,在父进程中调用一次,在父进程和子进程中各返回一次。fork在子进程中的返回值是0,而在父进程中的返回值则是子进程的id。 2)子进程在创建的时候会复制父进程的当前状态(PCB信息相同,用户态代码和数据也相同)。 3)程序运行的结果基本上是父子进程交替打印,但这也不是一定的,取决于系统中其它进程的运行情况和内核的调度算法。 2. 第一个fork: 子进程A被创建,之后从fork函数往下执行与父进程相同的代码,即后一个fork和printf 会被父进程和子进程A分别执行一次: 父进程打印的pid1和pid2是两个子进程的pid,即结果的第一行:pid1:3411, pid2:3412 子进程A打印的pid1和pid2是这个fork在子进程A中的返回(0)和子进程A中调用fork返回的pid,即结果的第二行:pid1:0, pid2:3413 3. 第二个fork: 这个fork会被父进程和子进程A都执行一遍。假设子进程B被主进程创建,子进程C被子进程A创建。子进程A也可以说是子进程C的父进程,为了避免混淆,我这里改叫主进程而不再使用父进程的概念。 子进程B的打印即结果的第三行:pid1:3411, pid2:0。其中,其中,pid1为复制的主进程的数据,pid2为该fork在子进程B中的返回。 子进程C的打印,即结果的最后一行:pid1:0, pid2:0。其中,pid1为复制的进程A的数据,pid2为该fork在子进程C内部的返回。

a和an的用法

a用在以辅音字母开头,或以读做辅音的元音字母开头的单词前面: a man一个男人 a university一所大学 a hat一顶帽子 a European一个欧洲人 a one-way street一条单行马路 an用在以元音字母(a,e,i,o,u)开头,或以不发音的h字母开头的单词前面:an apple一个苹果 an island一个岛 an uncle一位大叔 an onion一个洋葱 an egg一个鸡蛋 an hour一小时 an还用在发音以元音开头的单个字母前面: an L-plate一块“实习驾驶”车牌 an MP一个国会议员 an SOS一个呼救信号 an…x?一个x字母、X形的东西或未知数 a/an没有性的变化: a man一个男人 a woman一个女人 an actor一个男演员 an actress一个女演员

a table一张桌子 a/an不用在以下几种情况下: A 复数名词之前: a/an没有复数形式,所以a dog的复数是dogs,an egg的复数是eggs。 B 不可数名词之前(参见第13节): C 三餐名称之前,但这些名称前加形容词时除外: We have breakfast at eight. 我们8点钟吃早饭。 He gave us a good breakfast. 他请我们吃了一顿丰盛的早餐。 为了庆祝某事或特意为某人而举行的宴会之前要用冠词: I was invited to dinner(at their house, in the ordinary way). 他们邀请我吃饭(在他们家吃便饭)。 但是说: I was invited to a dinner given to welcome the new ambassador. 我被邀请参加欢迎新任大使的宴会。 A a/an和one(形容词) 1 计算时间、测量距离或重量等时,a/an或one可以用于单数的前面:£l=a/one pound一英镑 £ 1,000,000= a/one million pounds 100万英镑 (参见第三十六章。) 但是,请注意: The rent is £ 100 a week. 房租为每星期100英镑。

新手如何理解fork函数_华清远见

新手如何理解fork函数 我想,刚接触fork函数的时候,很多人都无法完全理解他,新手就更不用说了,为了让大家能正确理解fork函数,所以就写了一篇关于新手如何理解fork函数的文章。 首先我们来看看,什么是fork函数:计算机程序设计中的分叉函数。返回值:若成功调用一次则返回两个值,子进程返回0,父进程返回子进程标记;否则,出错返回-1。fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。 正题开始了,对于刚刚接触Unix/Linux操作系统,在Linux下编写多进程的人来说,fork是最难理解的概念之一:它执行一次却返回两个值。 首先我们来看下fork函数的原型: #i nclude #i nclude pid_t fork(void); 返回值: 负数:如果出错,则fork()返回-1,此时没有创建新的进程。最初的进程仍然运行。 零:在子进程中,fork()返回0 正数:在负进程中,fork()返回正的子进程的PID 其次我们来看下如何利用fork创建子进程。 创建子进程的样板代码如下所示: pid_t child; if((child = fork())<0) /*错误处理*/ else if(child == 0) /*这是新进程*/ else /*这是最初的父进程*/

fock函数调用一次却返回两次;向父进程返回子进程的ID,向子进程中返回0, 这是因为父进程可能存在很多过子进程,所以必须通过这个返回的子进程ID来跟踪子进程,而子进程只有一个父进程,他的ID可以通过getppid取得。 下面我们来对比一下两个例子: 第一个: #include #include int main() { pid_tpid; int count=0; pid = fork(); printf( "This is first time, pid = %d\n", pid ); printf( "This is second time, pid = %d\n", pid ); count++; printf( "count = %d\n", count ); if ( pid>0 ) { printf( "This is the parent process,the child has the pid:%d\n", pid ); } else if ( !pid ) { printf( "This is the child process.\n") }

fork系统调用

fork系统调用 (1) fork系统调用说明 fork系统调用用于从已存在进程中创建一个新进程,新进程称为子进程,而原进程称为父进程。fork调用一次,返回两次,这两个返回分别带回它们各自的返回值,其中在父进程中的返回值是子进程的进程号,而子进程中的返回值则返回 0。因此,可以通过返回值来判定该进程是父进程还是子进程。 使用fork函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间,包括进程上下文、进程堆栈、内存信息、打开的文件描述符、信号控制设定、进程优先级、进程组号、当前工作目录、根目录、资源限制、控制终端等,而子进程所独有的只有它的进程号、计时器等。因此可以看出,使用fork系统调用的代价是很大的,它复制了父进程中的数据段和堆栈段里的绝大部分内容,使得fork系统调用的执行速度并不很快。 fork的返回值这样设计是有原因的,fork在子进程中返回0,子进程仍可以调用getpid函数得到自己的进程ID,也可以调用getppid函数得到父进程的进程ID。在父进程中使用getpid函数可以得到自己的进程ID,然而要想得到子进程的进程ID,只有将fork的返回值记录下来,别无它法。 fork的另一个特性是所有由父进程打开的文件描述符都被复制到子进程中。父、子进程中相同编号的文件描述符在内核中指向同一个file结构体,也就是说,file结构体的引用计数要增加。 由于代码段(加载到内存的执行码)在内存中是只读的,所以父子进程可共用代码段,而数据段和堆栈段子进程则完全从父进程复制拷贝了一份。 (2)父进程进行fork系统调用时完成的操作 假设id=fork(),父进程进行fork系统调用时,fork所做工作如下: ①为新进程分配task_struct任务结构体内存空间。 ②把父进程task_struct任务结构体复制到子进程task_struct任务 结构体。 ③为新进程在其内存上建立内核堆栈。 ④对子进程task_struct任务结构体中部分变量进行初始化设置。 ⑤把父进程的有关信息复制给子进程,建立共享关系。 ⑥把子进程加入到可运行队列中。 ⑦结束fork()函数,返回子进程ID值给父进程中栈段变量id。 ⑧当子进程开始运行时,操作系统返回0给子进程中栈段变量id。(3)fork调用时所发生的事情

fork函数详解

一、fork入门知识 一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。 我们来看一个例子: /* * fork_test.c * version 1 * Created on: 2010-5-29 * Author: wangth */ #include #include int main () { pid_t fpid; //fpid表示fork函数返回的值 int count=0; fpid=fork(); if (fpid < 0) printf("error in fork!"); else if (fpid == 0) { printf("i am the child process, my process id is %d\n",getpid()); printf("我是爹的儿子\n");//对某些人来说中文看着更直白。 count++; } else { printf("i am the parent process, my process id is %d\n",getpid()); printf("我是孩子他爹\n"); count++; } printf("统计结果是: %d\n",count); return 0; } 运行结果是: i am the child process, my process id is 5574 我是爹的儿子 统计结果是: 1 i am the parent process, my process id is 5573

练习题一(1)

一、选择题 1. 下列哪种打开文件的方式不能修改文件已有的内容( B ) [A] r+ [B] r [C] w+ [D] a+ 2.以下哪种不是进程的状态( B ) [A] 运行态[B] 锁定态[C] 睡眠态[D] 停止态 3. 以读写方式打开一个已存在的标准I/O流时应指定哪个mode参数( B ) [A] r [B] r+ [C] w+ [D] a+ 4. fork()的返回值不可能是( C) [A] -1 [B] 0 [C] 1 [D] 大于10000的正整数 5. 常用来进行多任务同步的机制是(B ) [A]管道[B] 信号量[C] 信号[D] 共享内存 6. 下列哪个函数无法传递进程结束时的状态( A) [A]close [B] exit [C] _exit [D] return 7. 以下哪种用法可以等待接收进程号为pid的子进程的退出状态( A ) [A] waitpid(pid, &status, 0) [B] waitpid(pid, &status, WNOHANG) [C] waitpid(-1, &status, 0) [D] waitpid(-1, &status, WNOHANG) 8. What kind of IPC has the highest efficiency? (B) [A] semaphore [B] sharedmemory [C] fifo [D] message queue [E] signal 9. 下列对无名管道描述错误的是( C ) [A] 半双工的通信模式 [B] 有固定的读端和写端 [C] 可以使用lseek函数 [D] 只存在于内存中 10.下列对于有名管道描述错误的是( D ) [A] 可以用于互不相关的进程间 [B] 通过路径名来打开有名管道 [C] 在文件系统中可见 [D] 管道内容保存在磁盘上 11. 下列不属于用户进程对信号的响应方式的是( B ) [A] 忽略信号[B] 保存信号[C] 捕捉信号[D] 按缺省方式处理

父进程和子进程

父进程和子进程 子进程是父进程的复制品 Unix/linux系统中的进程创建是这样的,理解起来有点绕。 父进程先执行fork()系统调用,这个调用的结果是系统中多出了一个跟父进程内容完全一样的进程,这个新进程被称为子进程,当然该进程的PCB 中父进程指针是指向第一个进程的。 前后两个进程各自有自己的地址空间,形式上有点像把一个文件拷贝了一个副本。虽然资源也相互独立,但拷贝时父进程执行过程已生成的数据,子进程也拷了一份。说简单点像一个执行到半路的程序突然在系统中多出了一个孪生兄弟,什么都跟自己一样,但要管自己叫老爸。 当然这样的简单复制本身是没什么用处的。要让它发挥作用,还需要再执行exec( B )系统调用,这个调用可以让当前进程转而执行另一个可执行代码(一个新的程序)。简单的说进程本来在执行A程序,一旦执行到这个调用,就转而开始执行B程序。 至此,父子两进程就变的不一样了,但不管它们各自执行的什么代码,其父子关系不会改变,在父进程中可以使用子进程的进程ID(在执行fork()时的返回值中得到)来中止子进程的执行。当然子进程也可以因为自己的执行程序结束而终止执行

父进程和子进程先后执行的问题,是这样的,在fork之后,是父进程先执行,然后一个时间片到达之后就是子进程再执行了。 每一个进程都有一个父进程,当进程终止或者结束的时候,都会给父进程发送一个SIGCHLD信号,系统默认是父进程忽略这个信号,如果父进程希望被告知其子进程的这种状态改变,则应该捕获这个信号,捕捉函数一般是wait函数来取得子进程ID和子进程状态。 对于键盘上的Ctrl+按键的操作,一般是产生一个信号,然后进程捕捉这个信号。另外当然我们可以直接使用这些信号,通过kill命令,把信号发给相应的其他进程。 wait函数是父进程等待子进程结束,也就是说当子进程结束的时候会发送给父进程一个信号SIGCHID,这时候父进程通过wait函数接收到这个信号,这时候父进程就知道子进程结束了。这个正好用在shell解析器的编写里面,shell解析器作为父进程,而命令行命令作为子进程,当子进程结束的时候就会告诉父进程,这时候父进程就可以提示输入下一个命令了。

linux下fork的运行机制

linux下fork的运行机制 如下C程序,在linux下使用gcc编译: 1 #include "stdio.h" 2 #include "sys/types.h" 3 #include "unistd.h" int main() 4 { 5 pid_t pid1; 6 pid_t pid2; 7 pid1 = fork(); 8 pid2 = fork(); 10 printf("pid1:%d, pid2:%d\n", pid1, pid2); 11 } 要求如下: 已知从这个程序执行到这个程序的所有进程结束这个时间段内,没有其它新进程执行。 1、请说出执行这个程序后,将一共运行几个进程。 2、如果其中一个进程的输出结果是“pid1:1001, pid2:1002”,写出其他进程的输出结果(不考虑进程执行顺序)。 学习linux下fork的运行机制 预备知识 1、进程可以看做程序的一次执行过程。在linux下,每个进程有唯一的PID标识进程。PID是一个从1到32768的正整数,其中1一般是特殊进程init,其它进程从2开始依次编号。当用完32768后,从2重新开始。 2、linux中有一个叫进程表的结构用来存储当前正在运行的进程。可以使用“ps aux”命令查看所有正在运行的进程。 3、进程在linux中呈树状结构,init为根节点,其它进程均有父进程,某进程的父进程就是启动这个进程的进程,这个进程叫做父进程的子进程。 4、fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。 解题的关键 有了上面的预备知识,我们再来看看解题的关键。我认为,解题的关键就是要认识到fork将程序切成两段。看下图:

相关文档
最新文档