操作系统原理 | 实验2-进程控制(整理实验报告及知识点)

本文记录了操作系统原理实验的进程控制部分,涉及fork()、exec系列、waitpid()和exit()系统调用。通过编写程序,探讨并发执行、进程标识符的概念,分析实验结果,展示了并发执行的不同情况和进程间的交互。实验源代码包括fork1.c和fork2.c,其中fork2.c中子进程通过execvp()运行ls -al命令。
摘要由CSDN通过智能技术生成

从今天开始,记录本科一些课程的学习历程。本文记录的是操作系统原理实验课的第二个实验,实验源代码及知识点讲解大多来源于网上,文末将附相关链接。#自存# #侵删#

实验内容

  • 写一段程序,使用系统调用fork()来创建两个子进程,并由父进程重复显示字符某字符串和自己的标识数,而子进程则重复显示某字符串和自己的标识数。
  • 编写一段程序,使用系统调用fork()来创建一个子进程。子进程通过系统调用exec()更换自己的执行代码,显示新的代码后,调用exit()结束。而父进程则调用waitpid()等待子进程结束,并在子进程结束后显示子进程的标识符,然后正常结束。

实验知识点

进程 & 并发性 & 进程标识符

对于进程的定义有多种,其中较经典的定义有:

  • 进程是程序的一次执行;

  • 进程是一个程序及其数据在处理机上顺序执行所发生的活动;

  • 进程是具有独立功能的程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位。

并发性是进程的一个重要特征,也是OS的重要特征。引入进程的目的也正是为了使其进程实体能和其他进程实体并发执行。

程序(没有建立PCB)是不能参与并发执行的。

并发的实质是一个处理器在几个进程之间的多路复用 (多路复用比较出名的有时分复用,根据时间片调用不用的进程),是对有限的物理资源强制行使多用户共享,消除计算机部件之间的互等现象,以提高系统资源利用率。

宏观上,并发性反映一个时间段中几个进程都在同一处理器上处于运行还未运行结束的状态;微观上,任一时刻仅有一个进程在处理器上运行。

创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。

进程标识符是进程控制块(PCB)中的信息之一,用于唯一地表示一个进程。每一个进程都有一个唯一的数字标识符(即内部标识符),它通常是一个进程的序号,是由OS设置的。

进程的内部标识符可以通过getpid()函数获得,还有一个记录父进程pid的变量,可以通过getppid()函数获得变量的值。

fork()

#include<unistd.h>

特性总结:一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值(包括代码、数据和分配给进程的资源)都复制到新的新进程中。相当于克隆了一个自己,两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。

fork只拷贝下一个要执行的代码到新的进程,而不是从“include#…”开始拷贝的。

它仅仅被调用一次,却能够返回两次(父进程和子进程分别返回),并且它可能有三种不同的返回值:在父进程中,fork返回新创建子进程的进程ID;在子进程中,fork返回0;如果出现错误,fork返回一个负值。通过fork返回的值可以判断当前进程是子进程还是父进程。

exce系列

#include<unistd.h>

exce系统调用新程序覆盖调用它的进程的地址空间。exce把一个新的程序装入调用进程的内存空间,来改变调用进程的执行代码。此时,系统把代码段替换成新程序的代码,废弃原有的数据段和堆栈段,并为新程序分配新的数据段和堆栈段,唯一留下的只有进程号。对系统而言,还是同一个进程,只不过运行另一个可执行程序。

fork()和exce()组合是典型的Linux新进程产生模式,通常先用fork()创建新进程,然后新进程通过调用exce()系列执行自己的任务。

exec系列有:excel、excelp、excele、execv、execvp、execve。其中l表示长格式,v代表利用argv传参,e代表从envp传递环境变量,p代表从PATH指定路径搜索文件。以上六个函数的共同特点是,运行成功无返回(因为程序已被置换),运行失败返回-1,失败原因存于errno中。execve是系统调用函数,其他五个函数都是在用户空间中实现的,实际最终也是调用execve实现最终功能。

waitpid()

#include<sys/types.h>
#include<sys/wait.h>

这个函数会暂时停止目前进程的执行,直到有信号来到或子进程结束。waidpid()的返回值:如果执行成功,则返回子进程识别码,如果错误发生,则返回-1。失败原因存于errno中。

exit()

进程有生命周期,可通过给进程发送信号强行终止运行的进程,也可当完成任务后进程执行函数自动退出而消亡。无论在程序中什么位置,只要执行到exit系统调用,进程就会停止剩下的所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行。exit(status)的参数用来传递进程结束时的状态。0表示没意外的正常结束,其他的数值表示出现了错误,进程非正常结束。

调用exit()之前会检查文件的打开情况,把文件缓冲区的内容写回文件。如果要保证数据的完整性,要用exit()而不是_exit()。

实验源代码

// fork1.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>  // sys是系统路径。这个头文件包含了Unix/Linux系统的基本系统数据类型,含有size_t,time_t,pid_t等类型。
#include
(1)进程的软中断通信 #include #include #include #include int wait_flag; void stop(); main( ) { int pid1, pid2; // 定义两个进程号变量 signal(2,stop); // 或者 signal (14,stop); while((pid1 = fork( )) == -1); // 若创建子进程1不成功,则空循环 if(pid1 > 0) { // 子进程创建成功,pid1为进程号 while((pid2 = fork( )) == -1); // 创建子进程2 if(pid2 > 0) { wait_flag = 1; //sleep(1); // 父进程等待5秒 kill(pid1,SIGUSR1); // 杀死进程1 kill(pid2,SIGUSR2); // 杀死进程2 wait(0); wait(0); printf("\n Parent process is killed !!\n"); exit(0); // 父进程结束 } else { wait_flag = 1; signal(SIGUSR2,stop); // 等待进程2被杀死的中断号17 printf("\n Child process 2 is killed by parent !!\n"); exit(0); } } else { wait_flag = 1; signal(SIGUSR1,stop); // 等待进程1被杀死的中断号16 printf("\n Child process 1 is killed by parent !!\n"); exit(0); } } void stop() { wait_flag = 0; } (2)进程的管道通信 #include #include #include int pid1,pid2; // 定义两个进程变量 main( ) { int fd[2]; char OutPipe[100],InPipe[100]; // 定义两个字符数组 pipe(fd); // 创建管道 while((pid1 = fork( )) == -1); // 如果进程1创建不成功,则空循环 if(pid1 == 0) { lockf(fd[1],1,0); // 锁定管道 sprintf(OutPipe,"\n Child process 1 is sending message!\n"); write(fd[1],OutPipe,50); // 向管道写入数据 sleep(5); // 等待读进程读出数据 lockf(fd[1],0,0); // 解除管道的锁定 exit(0); // 结束进程1 } else { while((pid2 = fork()) == -1); // 若进程2创建不成功,则空循环 if(pid2 == 0) { lockf(fd[1],1,0); sprintf(OutPipe,"\n Child process 2 is sending message!\n"); write(fd[1],OutPipe,50); sleep(5); lockf(fd[1],0,0); exit(0); } else { wait(0); // 等待子进程1 结束 read(fd[0],InPipe,50); // 从管道中读出数据 printf("%s\n",InPipe); // 显示读出的数据 wait(0); // 等待子进程2 结束 read(fd[0],InPipe,50); printf("%s\n",InPipe); exit(0); // 父进程结束 } } }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值