fork()系统调用

合集下载

fork系统调用

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任务结构体中部分变量进行初始化设置。

linux中fork的作用

linux中fork的作用

linux中fork的作用在Linux中,fork(是一个非常重要的系统调用。

它的作用是创建一个新的进程,这个新的进程被称为子进程,而原始进程被称为父进程。

fork(系统调用会在父进程和子进程之间复制一份相同的当前执行状态,包括程序的代码、数据、堆栈以及其他相关资源。

当一个进程调用fork(时,操作系统会将当前的进程映像复制一份,包括进程的地址空间、文件描述符、信号处理器等。

然后操作系统会分配一个唯一的进程ID(PID)给子进程,父进程和子进程会分别返回子进程的PID和0。

子进程会从fork(调用的位置开始执行,而父进程则继续执行接下来的指令。

fork(的作用有以下几个方面:1. 多任务处理:通过fork(,一个进程可以生成多个子进程,每个子进程可以执行不同的任务。

这种多任务处理的能力是Linux操作系统的基石之一,它允许同时运行多个进程,从而提高系统的并发性和响应性能。

2. 进程间通信:fork(可以为不同的进程提供通信机制。

子进程可以通过进程间通信(IPC)机制与父进程进行数据交换,包括管道、消息队列、共享内存等。

这样实现了进程间的数据共享和协同工作。

3. 服务器模型:fork(在服务器模型中起到关键作用。

通过fork(,一个服务器进程可以创建多个子进程来处理客户端请求。

子进程在接收到请求后,可以独立地为客户端提供服务,这样能够极大地提高服务器的吞吐量和并发处理能力。

4. 资源管理:通过fork(,Linux可以对资源进行有效的管理。

当一个进程需要一个完全相同的副本来执行其他任务时,可以使用fork(来复制当前进程的状态。

这种状态的复制可以节省时间和资源,避免了重新加载和初始化的开销。

5. 守护进程创建:守护进程是在后台执行的长时间运行的进程,不依赖于任何终端。

通过调用fork(,父进程可以使自己成为一个后台进程,并终止自己,而子进程则变为一个孤儿进程并被init进程接管。

这样,守护进程就能够在系统启动后一直运行,提供服务。

进程管理实验报告分析(3篇)

进程管理实验报告分析(3篇)

第1篇一、实验背景进程管理是操作系统中的一个重要组成部分,它负责管理计算机系统中所有进程的创建、调度、同步、通信和终止等操作。

为了加深对进程管理的理解,我们进行了一系列实验,以下是对实验的分析和总结。

二、实验目的1. 加深对进程概念的理解,明确进程和程序的区别。

2. 进一步认识并发执行的实质。

3. 分析进程争用资源的现象,学习解决进程互斥的方法。

4. 了解Linux系统中进程通信的基本原理。

三、实验内容1. 使用系统调用fork()创建两个子进程,父进程和子进程分别显示不同的字符。

2. 修改程序,使每个进程循环显示一句话。

3. 使用signal()捕捉键盘中断信号,并通过kill()向子进程发送信号,实现进程的终止。

4. 分析利用软中断通信实现进程同步的机理。

四、实验结果与分析1. 实验一:父进程和子进程分别显示不同的字符在实验一中,我们使用fork()创建了一个父进程和两个子进程。

在父进程中,我们打印了字符'a',而在两个子进程中,我们分别打印了字符'b'和字符'c'。

实验结果显示,父进程和子进程的打印顺序是不确定的,这是因为进程的并发执行。

2. 实验二:每个进程循环显示一句话在实验二中,我们修改了程序,使每个进程循环显示一句话。

实验结果显示,父进程和子进程的打印顺序仍然是随机的。

这是因为并发执行的进程可能会同时占用CPU,导致打印顺序的不确定性。

3. 实验三:使用signal()捕捉键盘中断信号,并通过kill()向子进程发送信号在实验三中,我们使用signal()捕捉键盘中断信号(按c键),然后通过kill()向两个子进程发送信号,实现进程的终止。

实验结果显示,当按下c键时,两个子进程被终止,而父进程继续执行。

这表明signal()和kill()在进程控制方面具有重要作用。

4. 实验四:分析利用软中断通信实现进程同步的机理在实验四中,我们分析了利用软中断通信实现进程同步的机理。

操作系统面试题(三)

操作系统面试题(三)

操作系统⾯试题(三)●请你来说⼀说协程参考回答:1、概念:协程,⼜称微线程,纤程,英⽂名Coroutine。

协程看上去也是⼦程序,但执⾏过程中,在⼦程序内部可中断,然后转⽽执⾏别的⼦程序,在适当的时候再返回来接着执⾏。

例如:def A() :print '1'print '2'print '3'def B() :print 'x'print 'y'print 'z'由协程运⾏结果可能是12x3yz。

在执⾏A的过程中,可以随时中断,去执⾏B,B也可能在执⾏过程中中断再去执⾏A。

但协程的特点在于是⼀个线程执⾏。

2)协程和线程区别那和多线程⽐,协程最⼤的优势就是协程极⾼的执⾏效率。

因为⼦程序切换不是线程切换,⽽是由程序⾃⾝控制,因此,没有线程切换的开销,和多线程⽐,线程数量越多,协程的性能优势就越明显。

第⼆⼤优势就是不需要多线程的锁机制,因为只有⼀个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执⾏效率⽐多线程⾼很多。

3)其他在协程上利⽤多核CPU呢——多进程+协程,既充分利⽤多核,⼜充分发挥协程的⾼效率,可获得极⾼的性能。

Python对协程的⽀持还⾮常有限,⽤在generator中的yield可以⼀定程度上实现协程。

虽然⽀持不完全,但已经可以发挥相当⼤的威⼒了。

●系统调⽤是什么,你⽤过哪些系统调⽤参考回答:1)概念:在计算机中,系统调⽤(英语:system call),⼜称为系统呼叫,指运⾏在使⽤者空间的程序向操作系统内核请求需要更⾼权限运⾏的服务。

系统调⽤提供了⽤户程序与操作系统之间的接⼝(即系统调⽤是⽤户程序和内核交互的接⼝)。

操作系统中的状态分为管态(核⼼态)和⽬态(⽤户态)。

⼤多数系统交互式操作需求在内核态执⾏。

如设备IO操作或者进程间通信。

特权指令:⼀类只能在核⼼态下运⾏⽽不能在⽤户态下运⾏的特殊指令。

《操作系统原理》习题及参考答案

《操作系统原理》习题及参考答案

3.2
14.4
17.6
9.2
2.9
C
9:00(9.0)
1
17.6
18.6
9.6
9.6
短作业优先算法:
作业号
进入输入 需运行时 开始运行 完成时间 周转时间 带权周转
井时间 间(小时) 时间
时间
A
8:00(8.0)
6.4
8.0
14.4
6.4
1
5
B
8:24(8.4)
3.2
15.4
18.6
10.2
3.2
15. 设一个飞机航班售票系统有 n 个售票处,每个售票处通过终端访问系统的公共数据 区。假定公共数据区中的一些单元 Aj(j=1,2,3,…)分别存放某月某日某次航班的余票数。 用 P1,P2,…,Pn 表示个售票处为旅客服务时的处理进程; R1, R2, R3…, Rn 为各进程执 行时所用的工作单元。用 PV 操作和信号量保证售票系统的正确并发执行。
解:(1)设信号量 S2:=0; S3:=0; S4:=0;
P1:
P2:
P3:
……..
P(S2)
P(S3)
……..
……..
……..
V(S2)
…….
…….
V(S3)
V(S4)
V(S4)
(2)设信号量 S3:=0; S4:=0; S5:=0; S6:=0;
P1: …….. …….. …….. V(S3)
x
y
z
S1
S2
P1 x:=0
0
0
0
P1 x:=x+2
2
0
0
0
P1 P(S1)

操作系统常用系统调用

操作系统常用系统调用

1.fork()功能:创建一个新的进程. 语法:#include #includepid_t fork(); 说明:本系统调用产生一个新的进程, 叫子进程, 是调用进程的一个复制品. 调用进程叫父进程, 子进程继承了父进程的几乎所有的属性:2.waitpid()功能:等待指定进程号的子进程的返回并修改状态语法:#include #includepid_t waitpid(pid,stat_loc,options) pid_t pid; int *stat_loc,options; 说明:当pid等于-1,options等于0时,该系统调用等同于wait().否则该系统调用的行为由参数pid和options决定. pid指定了一组父进程要求知道其状态的子进程: -1:要求知道任何一个子进程的返回状态. >0:要求知道进程号为pid值的子进程的状态.0) { waitpid(pid,&stat_loc,0);/*父进程等待进程号为pid的子进程的返回*/ }else { /*子进程的处理过程*/ exit(1);}/*父进程*/ printf("stat_loc is [ d]\n",stat_loc); /*字符串"stat_loc is [1]"将被打印出来*/3.exit()功能:终止进程. 语法:#include void exit(status) int status; 说明:调用进程被该系统调用终止.引起附加的处理在进程被终止前全部结束.返回值:无4.signal()功能:信号管理功能语法:#include void (*signal(sig,disp))(int) int sig; void (*disp)(int); void (*sigset(sig,disp))(int) int sig; void (*disp)(int); int sighold(sig) int sig; int sigrelse(sig) int sig; int sigignore(sig) int sig; int sigpause(sig) int sig; 说明:这些系统调用提供了应用程序对指定信号的简单的信号处理. signal()和sigset()用于修改信号定位.参数sig指定信号(除了SIGKILL和SIGSTOP,这两种信号由系统处理,用户程序不能捕捉到). disp指定新的信号定位,即新的信号处理函数指针.可以为SIG_IGN,SIG_DFL或信号句柄地址. 若使用signal(),disp是信号句柄地址,sig不能为SIGILL,SIGTRAP或SIGPWR,收到该信号时,系统首先将重置sig的信号句柄为SIG_DFL,然后执行信号句柄. 若使用sigset(),disp是信号句柄地址,该信号时,系统首先将该信号加入调用进程的信号掩码中,然后执行信号句柄.当信号句柄运行结束后,系统将恢复调用进程的信号掩码为信号收到前的状态.另外,使用sigset()时,disp为SIG_HOLD,则该信号将会加入调用进程的信号掩码中而信号的定位不变. sighold()将信号加入调用进程的信号掩码中. sigrelse()将信号从调用进程的信号掩码中删除. sigignore()将信号的定位设置为SIG_IGN. sigpause()将信号从调用进程的信号掩码中删除,同时挂起调用进程直到收到信号. 若信号SIGCHLD的信号定位为SIG_IGN,则调用进程的子进程在终止时不会变成僵死进程.调用进程也不用等待子进程返回并做相应处理. 返回值:调用成功则signal()返回最近调用signal()设置的disp的值. 否则返回SIG_ERR.例子一:设置用户自己的信号中断处理函数,以SIGINT信号为例: int flag=0; void myself() {flag=1;printf("get signal SIGINT\n"); /*若要重新设置SIGINT信号中断处理函数为本函数则执行以*下步骤*/ void (*a)(); a=myself;signal(SIGINT,a);flag=2;}main(){while (1) { sleep(2000); /*等待中断信号*/ if (flag==1) { printf("skip system call sleep\n"); exit(0);}if (flag==2) { printf("skip system call sleep\n"); printf("waiting for next signal\n"); }}}5.kill()功能:向一个或一组进程发送一个信号. 语法:#include #includeint kill(pid,sig); pid_t pid; int sig; 说明:本系统调用向一个或一组进程发送一个信号,该信号由参数sig指定,为系统给出的信号表中的一个.若为0(空信号)则检查错误但实际上并没有发送信号,用于检查pid的有效性. pid指定将要被发送信号的进程或进程组.pid若大于0,则信号将被发送到进程号等于pid 的进程;若pid等于0则信号将被发送到所有的与发送信号进程同在一个进程组的进程(系统的特殊进程除外);若pid小于-1,则信号将被发送到所有进程组号与pid绝对值相同的进程;若pid等于-1,则信号将被发送到所有的进程(特殊系统进程除外). 信号要发送到指定的进程,首先调用进程必须有对该进程发送信号的权限.若调用进程有合适的优先级则具备有权限.若调用进程的实际或有效的UID等于接收信号的进程的实际UID或用setuid()系统调用设置的UID,或sig等于SIGCONT同时收发双方进程的会话号相同,则调用进程也有发送信号的权限. 若进程有发送信号到pid指定的任何一个进程的权限则调用成功, 否则调用失败,没有信号发出.返回值:调用成功则返回0,否则返回-1. 例子:假设前一个例子进程号为324,现向它发一个SIGINT信号,让它做信号处理: kill((pid_t)324,SIGINT);6.alarm()功能:设置一个进程的超时时钟. 语法:#include unsigned int alarm(sec) unsigned int sec; 说明:指示调用进程的超时时钟在指定的时间后向调用进程发送一个SIGALRM信号.设置超时时钟时时间值不会被放入堆栈中,后一次设置会把前一次(还未到超时时间)冲掉. 若sec为0,则取消任何以前设置的超时时钟. fork()会将新进程的超时时钟初始化为0.而当一个进程用exec()族系统调用新的执行文件时,调用前设置的超时时钟在调用后仍有效. 返回值:返回上次设置超时时钟后到调用时还剩余的时间秒数. 例子:int flag=0; void myself() {flag=1;printf("get signal SIGALRM\n"); /*若要重新设置SIGALRM信号中断处理函数为本函数则执行*以下步骤*/ void (*a)(); a=myself;signal(SIGALRM,a);flag=2;}main(){alarm(100); /*100秒后发超时中断信号*/ while (1) { sleep(2000); /*等待中断信号*/ if (flag==1) { printf("skip system call sleep\n"); exit(0);}if (flag==2) { printf("skip system call sleep\n"); printf("waiting for next signal\n"); }}}7.system()功能:产生一个新的进程, 子进程执行指定的命令. 语法:#include #includeint system(string) char *string; 说明:本调用将参数string传递给一个命令解释器(一般为sh)执行, 即string被解释为一条命令, 由sh执行该命令.若参数string为一个空指针则为检查命令解释器是否存在. 该命令可以同命令行命令相同形式, 但由于命令做为一个参数放在系统调用中, 应注意编译时对特殊意义字符的处理. 命令的查找是按PATH环境变量的定义的. 命令所生成的后果一般不会对父进程造成影响. 返回值:当参数为空指针时, 只有当命令解释器有效时返回值为非零. 若参数不为空指针, 返回值为该命令的返回状态(同waitpid())的返回值. 命令无效或语法错误则返回非零值,所执行的命令被终止. 其他情况则返回-1. 例子:char command[81]; int i; for (i=1;i0) { wait((int *)0); /*父进程等待子进程的返回*/ }else { /*子进程处理过程*/ exit(0);}。

linux中fork的语法及用法

linux中fork的语法及用法

在Linux中,fork()函数是用于创建一个新进程的系统调用。

以下是fork()函数的语法和用法:
语法:
fork()`函数返回两次:一次是在父进程中,另一次是在新创建的子进程中。

在父进程中,fork()函数返回新创建子进程的进程ID(PID)。

在子进程中,fork()函数返回0。

如果fork()函数出现错误,它会返回一个负值,通常为-1。

用法:
1.在父进程中调用fork()函数,创建一个子进程。

2.父进程和子进程从fork()函数返回处开始执行。

3.父进程和子进程可以继续执行不同的代码路径,实现并行执行。

4.可以通过wait()或waitpid()函数等待子进程结束,以回收子进程的资
源。

示例:
在上述示例中,父进程和子进程分别打印不同的消息,并使用wait()函数等待子进程结束。

注意,在子进程中,我们使用return 0;语句来结束子进程的执行。

fork()函数的理解

fork()函数的理解

对于刚刚接触Unix/Linux操作系统,在Linux下编写多进程的人来说,fork是最难理解的概念之一:它执行一次却返回两个值。

首先我们来看下fork函数的原型:#i nclude <sys/types.h>#i nclude <uni ST d.h>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 <unistd.h>#include <stdio.h>int main(){pid_t pid;int count=0;pid = fork();printf( "This is first time, pid = %d\n", pid );printf( "This is sec ON d 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")}else{printf( "fork failed.\n" );}printf( "This is third time, pid = %d\n", pid );printf( "This is fouth time, pid = %d\n", pid );return 0;}运行结果如下:问题:这个结果很奇怪了,为什么printf的语句执行两次,而那句“count++;”的语句却只执行了一次接着看:#include <unistd.h>#include <stdio.h>int main(void){pid_t pid;int count=0;pid = fork();printf( "Now, the pid returned by calling fork() is %d\n", pid );if ( pid>0 ){printf( "This is the parent proc ESS,the child has the pid:%d\n", pid );printf( "In the parent process,count = %d\n", count );}else if ( !pid ){printf( "This is the child process.\n");printf( "Do your own things here.\n" );count ++;printf( "In the child process, count = %d\n", count );}else{printf( "fork failed.\n" );}return 0;}运行结果如下:现在来解释上面提出的问题。

Linux进程控制原语

Linux进程控制原语

Linux/UNIX进程控制原语Linux/UNIX进程控制原语-1 进程控制原语
(2)exec系统调用 系统调用 格式: 六种 六种) 格式:(六种)
int execl(path,arg0,arg1,…,argn,(char *)0)
char *path, *arg0, *arg1, …, *argn ; exec调用进程的正文段被指定的目标文件的正文段 调用进程的正文段被指定的目标文件的正文段 所覆盖,其属性的变化方式与fork成功后从父进程 所覆盖,其属性的变化方式与 成功后从父进程 那里继承属性的方式几乎是一样的。 那里继承属性的方式几乎是一样的。系统中绝大多 数命令都是通过exec来执行的,不但 来执行的, 数命令都是通过 来执行的 不但shell进程所 进程所 创建的子进程使用它来执行用户命令, 创建的子进程使用它来执行用户命令,shell进程本 进程本 身和它的祖先进程也是用exec来启动执行的。 来启动执行的。 身和它的祖先进程也是用 来启动执行的
(6)程序执行说明 (6)程序执行说明 该程序说明主进程创建了一个子程序后, 该程序说明主进程创建了一个子程序后,二 个进程并发执行的情况。 个进程并发执行的情况。 主进程在执行fork系统调用前是一个进程, 主进程在执行 系统调用前是一个进程, 系统调用前是一个进程 执行fork系统调用后,系统中又增加了一个与 系统调用后, 执行 系统调用后 原过程环境相同的子进程, 原过程环境相同的子进程,它们执行程序中 fork语句以后相同的程序,父和子进程 中都有 语句以后相同的程序, 语句以后相同的程序 自己的变量pid,但它们的值不同,它是 自己的变量 ,但它们的值不同,它是fork调 调 用后的返回值,父进程的pid为大于 的值, 为大于0的值 用后的返回值,父进程的 为大于 的值,它 代表新创建子进程的标识符,而子进程的pid为 代表新创建子进程的标识符,而子进程的 为 0。这样父子进程执行相同一个程序,但却执行 。这样父子进程执行相同一个程序, 不同的程序段。子进程执行if(pid= = 0)以后的 不同的程序段。子进程执行 以后的 大括号内的程序, 语句; 大括号内的程序,即execlp语句;而父进程执 语句 以后的大括号内的程序。 行else以后的大括号内的程序。 以后的大括号内的程序

posix接口标准

posix接口标准

posix接口标准一、概述POSIX(Portable Operating System Interface)接口标准是由IEEE和ISO/IEC联合制定的一组操作系统接口规范,旨在实现不同操作系统之间的兼容性和互操作性。

其中,POSIX API(应用程序接口)是POSIX标准的核心组成部分,它定义了一组常用的系统调用,为开发人员提供了访问操作系统功能的途径。

二、posix接口标准的主要内容1. 进程管理(1)fork():创建一个新进程,复制父进程的映像。

(2)exec():加载可执行文件,替换当前进程的映像。

(3)exit():终止进程。

(4)wait():等待子进程结束。

(5)signal():设置信号处理函数。

2. 文件操作(1)open():打开文件。

(2)read()、write():读写文件。

(3)lseek():改变文件偏移量。

(4)close():关闭文件。

(5)stat()、lstat()、fstat():获取文件属性。

3. 进程间通信(1)pipe():创建管道。

(2)readline()、read():从管道读取数据。

(3)write():向管道写入数据。

(4)fork()+exec():使用管道执行子进程。

4. 信号处理(1)signal():设置信号处理函数。

(2)raise():发送信号。

(3)kill():发送信号给进程或线程。

5. 线程管理(1)pthread_create():创建线程。

(2)pthread_join():等待线程结束。

(3)pthread_exit():退出线程。

(4)pthread_setname_np():设置线程名称。

三、posix接口标准的特点与应用场景POSIX接口标准具有以下特点:1. 兼容性好:POSIX接口标准遵循统一的标准规范,不同操作系统之间的兼容性较好。

2. 易用性:POSIX接口提供了常用的系统调用,方便开发人员快速实现功能。

fork

fork
1)fork()系统调用是创建一个新进程的首选方式,fork的返回值要么是0,要么是非0,父进程与子进程的根本区别在于fork函数的返回值.
2)vfork()系统调用除了能保证用户空间内存不会被复制之外,它与fork几乎是完全相同的.vfork存在的问题是它要求子进程立即调用exec,
而不用修改任何内存,这在真正实现的时候要困难的多,尤其是考虑到exec调用有可能失败.
./test
count= 1
count= 1
Segmentation fault (core dumped)
分析:
通过将fork()换成vfork(),由于vfork()是共享数据段,为什么结果不是2呢,答案是:
vfork保证子进程先运行,在它调用 exec 或 exit 之后父进程才可能被调度运行.如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁.
示例代码:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char ** argv )
{
int pid = fork();
if(pid == -1 )
{
// print("error!");
} else if( pid = =0 ) {
3)做最后的修改,在子进程执行时,调用_exit(),程序如下:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
int main(void)

UNIX进程管理

UNIX进程管理

一、Unix进程控制1、进程的创建与终止进程是操作系统中活跃着的“生命”,从创建到终止一代又一代,生生不息。

UNIX 系统中创建进程的方法是用系统调用fork()。

调用系统调用 fork()的进程是父进程,所创建的新进程为子进程。

除进程0 之外,系统中所有的进程都是系统调用fork()创建的。

系统调用 fork()的实现过程首先是由内核为新进程在进程表中分配一个表项并给新进程一个唯一的进程标识符PID;然后通过拷贝父进程的进程映象来创建一新进程,新进程将获得其父进程地址空间的一份拷贝;最后增加与该进程相关联的文件表和索引节点表的引用数并将子进程的进程标志返回给父进程,收到父进程返回信号则标志新进程创建完毕。

fork()系统调用生成子进程的步骤见图8.2-1,包含如下步骤:(1)如果系统内存够,则能创建进程;否则调用退出;(2)为要创建的进程分配一个空闲的进程表项和唯一的进程标识符PID;(3)如果进程所在的用户其进程数没超过系统限制,则能创建进程;否则调用退出;(4)设置进程状态为创建,拷贝父进程表项中数据到进程表项中;(5)将当前目录的索引节点和改变的根目录的引用数加 1,文件表中打开文件的引用数加1;(6)拷贝父进程上下文到进程的上下文;(7)如果正在执行的是其父进程则设置进程状态为就绪,否则初始化u 区的计时域。

2、子进程创建后拷贝其父进程的上下文,并且还可用父进程的当前目录和根目录以及已打开的文件,只是这些的引用计数要加1。

3、当父进程创建子进程时希望子进程结束后能把控制返回给父进程,所以子进程不能覆盖父进程给予的控制区。

当进程任务完成后,为了收回进程所占用的系统资源和减少父进程的负担,进程可以用系统调用exit()来实现进程的自我终止。

进程终止可以是正常情况下,也可以在非正常情况下。

有如下几个步骤:(1)关闭进程的软中断信号;(2)如果是与控制终端相连的进程组组长,则向本组进程发出挂起信号。

fork 用法

fork 用法

fork 用法fork 是一个系统调用,用于创建一个新的进程。

新的进程是原始进程(父进程)的一个副本,称为子进程。

这两个进程在几乎所有方面都是相同的,包括代码、数据和上下文。

在编程中,fork 通常用于创建一个新的进程,以便在子进程中执行不同的任务。

基本用法:#include <unistd.h>#include <stdio.h>int main() {pid_t pid = fork();if (pid == -1) {// 处理 fork 失败的情况perror("fork");return 1;}if (pid == 0) {// 子进程执行的代码printf("This is the child process (PID=%d)\n", getpid());} else {// 父进程执行的代码printf("This is the parent process (PID=%d), child PID=%d\n", getpid(), pid);}return 0;}注意事项:fork 返回两次,一次在父进程中返回子进程的PID,另一次在子进程中返回0。

在父子进程中的变量和状态是相互独立的,它们不会相互影响。

在fork 之后,通常会使用exec 函数族在子进程中加载新的程序。

父子进程的执行顺序和执行时间是不确定的,取决于操作系统的调度。

示例:在子进程中执行其他程序#include <unistd.h>#include <stdio.h>#include <sys/wait.h>int main() {pid_t pid = fork();if (pid == -1) {perror("fork");return 1;}if (pid == 0) {// 子进程中执行其他程序execl("/bin/ls", "ls", "-l", NULL);} else {// 等待子进程结束wait(NULL);printf("Parent process done.\n");}return 0;}这个例子中,父进程创建了一个子进程,子进程通过 execl 加载了 /bin/ls 程序。

操作系统实验---进程的创建与控制

操作系统实验---进程的创建与控制

实验报告实验题目姓名:学号:课程名称:操作系统实验所在学院:信息科学与工程学院专业班级:计算机任课教师:核心为fork( )完成以下操作:(1)为新进程分配一进程表项和进程标识符进入fork( )后,核心检查系统是否有足够的资源来建立一个新进程。

若资源不足,则fork( )系统调用失败;否则,核心为新进程分配一进程表项和唯一的进程标识符。

(2)检查同时运行的进程数目超过预先规定的最大数目时,fork( )系统调用失败。

(3)拷贝进程表项中的数据将父进程的当前目录和所有已打开的数据拷贝到子进程表项中,并置进程的状态为“创建”状态。

(4)子进程继承父进程的所有文件对父进程当前目录和所有已打开的文件表项中的引用计数加1。

(5)为子进程创建进程上、下文进程创建结束,设子进程状态为“内存中就绪”并返回子进程的标识符。

(6)子进程执行虽然父进程与子进程程序完全相同,但每个进程都有自己的程序计数器PC(注意子进程的注意子进程的PC 开始位置),然后根据pid 变量保存的fork( )返回值的不同,执行了不同的分支语句。

四、实验过程、步骤及内容1、编写一段程序,使用系统调用fork( )创建两个子进程。

当此程序运行时,在系统中有一个父进程和两个子进程活动。

让每一个进程在屏幕上显示一个字符:父进程显示'a',子进程分别显示字符'b'和字符'c'。

试观察记录屏幕上的显示结果,并分析原因。

2、修改上述程序,每一个进程循环显示一句话。

子进程显示'daughter …'及'son ……',父进程显示'parent ……',观察结果,分析原因。

3、用fork( )创建一个进程,再调用exec( )用新的程序替换该子进程的内容4、用fork( )建立如下形式的进程树:A进程B进程C进程D进程各个进程中都打印出本身PID 和其父进程的PID,并用wait( )来控制进程执行顺序,打印出正确和期望的结果。

linux创建进程的方法

linux创建进程的方法

linux创建进程的方法
在Linux系统中,创建进程的方法有多种,其中最常用的方法是使用fork()系统调用。

下面是详细的创建进程的步骤:
1. 导入头文件
在程序中导入头文件<unistd.h>,该头文件中包含了fork()系统调用的声明。

2. 调用fork()系统调用
使用fork()系统调用创建一个新的进程。

fork()系统调用会返回两次,一次在父进程中返回子进程的PID,另一次在子进程中返回0。

3. 判断进程类型
根据fork()系统调用的返回值判断当前进程是父进程还是子进程。

如果返回值大于0,则表示当前进程是父进程,返回值为子进程的PID;如果返回值为0,则表示当前进程是子进程。

4. 编写父进程代码
在父进程中编写需要执行的代码。

通常情况下,父进程会等待子进程执行完毕后再继续执行。

5. 编写子进程代码
在子进程中编写需要执行的代码。

通常情况下,子进程会执行一些与父进程不同的操作。

6. 退出进程
在进程执行完毕后,使用exit()系统调用退出进程。

在父进程中,可以使用wait()系统调用等待子进程执行完毕后再退出。

以上就是在Linux系统中创建进程的详细步骤。

需要注意的是,创建进程时需要
注意进程间的通信和同步问题,以确保程序的正确性和稳定性。

fork()的用法

fork()的用法

fork()的用法
fork() 是一个用于创建新进程的系统调用。

具体来说,它会复制当前进程,然后创建一个与原进程几乎完全相同的新进程。

新进程(子进程)会继承父进程的所有资源,包括代码、数据和系统资源。

fork() 的基本用法如下:
1. 调用 fork() 函数,它会返回两次:一次是在父进程中,返回新创建子进程的 PID;另一次是在子进程中,返回 0。

2. 在父进程中,fork() 返回新创建子进程的 PID,可以通过这个 PID 对子进程进行操作。

3. 在子进程中,fork() 返回 0,可以通过返回值来区分当前是父进程还是子进程。

fork() 的常见用法包括:
1. 创建新的子进程:通过调用 fork() 函数,可以创建一个与原进程几乎完全相同的新进程。

新进程会继承父进程的所有资源,包括代码、数据和系统资源。

2. 实现多线程:fork() 可以用来实现多线程编程。

在每个线程中调用 fork() 函数,可以创建多个子进程,从而实现并发执行。

3. 实现并行计算:通过 fork() 函数创建多个子进程,每个子进程执行不同的任务,可以实现并行计算,提高程序的执行效率。

需要注意的是,fork() 函数的使用需要谨慎,因为它涉及到进程的创建和复制。

如果使用不当,可能会导致资源泄漏、竞争条件等问题。

因此,在使用fork() 函数时需要仔细考虑程序的逻辑和安全性。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

fork系统调用
分类:LINUX
1.预备知识
不妨简单理解为,一个进程表示的,就是一个可执行程序的一次执行过程中的一个状态。

操作系统对进程的管理,典型的情况,是通过进程表完成的。

进程表中的每一个表项,记录的是当前操作系统中一个进程的情况。

对于单 CPU的情况而言,每一特定时刻只有一个进程占用 CPU,但是系统中可能同时存在多个活动的(等待执行或继续执行的)进程。

一个称为“程序计数器(program counter, pc)”的寄存器,指出当前占用
CPU的进程要执行的下一条指令的位置。

当分给某个进程的CPU时间已经用完,操作系统将该进程相关的寄存器的值,保存到该进程在进程表中对应的表项里面;把将要接替这个进程占用 CPU的那个
进程的上下文,从进程表中读出,并更新相应的寄存器(这个过程称为“上下文
交换(process context switch)”,实际的上下文交换需要涉及到更多的数据,那和fork无关,不再多说,主要要记住程序寄存器pc指出程序当前已经执行到哪里,
是进程上下文的重要内容,换出 CPU的进程要保存这个寄存器的值,换入CPU的
进程,也要根据进程表中保存的本进程执行上下文信息,更新这个寄存器)。

2.fork系统调用
当你的程序执行到下面的语句:
pid=fork();
操作系统创建一个新的进程(子进程),并且在进程表中相应为它建立一个新的表项。

新进程和原有进程的可执行程序是同一个程序;上下文和数据,绝大部分就是原进程(父进程)的拷贝,但它们是两个相互独立的进程!此时程序寄存器pc,在父、子进程的上下文中都声称,这个进程目前执行到fork调用即将返回
(此时子进程不占有CPU,子进程的pc不是真正保存在寄存器中,而是作为进程
上下文保存在进程表中的对应表项内)。

问题是怎么返回,在父子进程中就分道
扬镳。

父进程继续执行,操作系统对fork的实现,使这个调用在父进程中返回刚刚
创建的子进程的pid(一个正整数),所以下面的if语句中pid<0, pid==0的两个分
支都不会执行。

所以输出i am the parent process...
子进程在之后的某个时候得到调度,它的上下文被换入,占据 CPU,操作系
统对fork的实现,使得子进程中fork调用返回0。

所以在这个进程(注意这不是父进程了哦,虽然是同一个程序,但是这是同一个程序的另外一次执行,在操作系统中这次执行是由另外一个进程表示的,从执行的角度说和父进程相互独立)中
pid=0。

这个进程继续执行的过程中,if语句中pid<0不满足,但是pid==0是true。

所以输出i am the child process...
我想你比较困惑的就是,为什么看上去程序中互斥的两个分支都被执行了。

在一个程序的一次执行中,这当然是不可能的;但是你看到的两行输出是来自两个
进程,这两个进程来自同一个程序的两次执行。

3.我们来给出详细的注释
#include
#include
intmain(void)
{
pid_tpid;
int count=0;
/*此处,执行fork调用,创建了一个新的进程,
这个进程共享父进程的数据和堆栈空间等,这之后的代码指令为子进程创建了一个拷贝。

fork调用是一个复制进程,fork 不象线程需提供一个函数做为入口,
fork调用后,新进程的入口就在 fork的下一条语句。

*/
pid = fork();
/*此处的pid的值,可以说明fork调用后,目前执行的是那父进程还是子进程*/
printf( "Now, the pid returned by calling fork() is %d\n", pid );
if ( pid>0 )
{
/*当fork在子进程中返回后,fork调用又向父进程中返回子进程的pid,如是该段代码被执行,但是注意的事,count仍然为0,
因为父进程中的count始终没有被重新赋值,
这里就可以看出子进程的数据和堆栈空间和父进程是独立的,而不是共享数据*/
printf( "This is the parent process,the child has the pid:%d\n", pid );
printf( "In the parent process,count = %d\n", count );
}
else if ( !pid )
{ /*在子进程中对count进行自加1的操作,但是并没有影响到父进程中的count值,父进程中的count值仍然为0*/
printf( "This is the child process.\n");
printf( "Do your own things here.\n" );
count++;
printf( "In the child process, count = %d\n", count );
}
else
{
printf( "fork failed.\n" );
}
return 0;
}。

相关文档
最新文档