操作系统实验报告

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

操作系统实验报告
学号
姓名
班级
实验一实验报告
【实验名称】:并发程序设计(实验1)
【实验目的】:掌握在程序中创建新进程的方法,观察并理解多道程序并发执行的现象。

【实验原理】:fork():建立子进程。

子进程得到父进程地址空间的一个复制。

返回值:成功时,该函数被调用一次,但返回两次,fork()对子
进程返回0,对父进程返回子进程标识符(非0值)。

不成功时对
父进程返回-1,没有子进程。

【实验内容】:首先分析一下程序运行时其输出结果有哪几种可能性,然后实际调试该程序观察其实际输出情况,比较两者的差异,分析其中的原
因。

void main (void)
{ int x=5;
if( fork( ) )
{
x+=30;
printf (“%d\n”,x);
}
else
printf(“%d\n”,x);
printf((“%d\n”,x);
}
【实验要求】:每个同学必须独立完成本实验、提交实验报告、源程序和可执行程序。

实验报告中必须包含预计的实验结果,关键代码的分析,
调试记录,实际的实验结果,实验结果分析等内容。

【预计的实验结果】
35
5
35
5
【关键代码分析】
1,代码主要由fork()函数和一个if else 条件分支语句组成。

2,fork()函数,它是Linux的系统调用。

函数定义:
int fork( void );
返回值:
子进程中返回0,父进程中返回子进程ID,出错返回-1
函数说明:
一个现有进程可以调用fork函数创建一个新进程。

由fork创建的新进程被称为子进程(child process)。

fork函数被调用一次但返回两次。

两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。

子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。

注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间,它们之间共享的存储空间只有代码段。

linux将复制父进程的地址空间内容给子进程,因此,子进程有了独立的地址空间。

3,父进程和子进程的代码段都是上面的所有代码,由定义可知不过子进程的代码只从创建此子进程那里开始执行。

也就是从if( fork( ) )语句开始,出现了子进程,两个进程并发执行。

当这个程序执行if(fork()) 时,操作系统创建一个新的进程(子进程),并且在进程表中相应为它建立一个新的PCB表项。

其中子进程从父进程继承到了大部分的参数。

也有独有的参数,如进程号等。

但是此后他们是独立的两个进程。

在子进程里创建的东西是子进程的,在父进程创建的东西是父进程
的。

可以完全看成普通的两个进程。

所以在执行printf((“%d\n”,x);
的时候,父子进程当然都会执行它,因为他们本身程序段里都有这句代码。

【调试记录】
在红帽终端里做gdb调试
在第五行加入断点,执行run得到5 5,这是子进程执行的结果。

再执行next得到35 35,这是父进程的结果。

这里可以看出,由父进程创建的子进程先执行完毕,但是宏观上是并发执行。

【实际的实验结果】
5
5
35
35
【实验结果分析】
从实际结果来看,子进程比父进程先执行完,但是由fork函数,我们可知,两者优先级应该是一样的。

至于哪个可能先执行,可能和操作系统的具体调度算法有关。

当实验超过一定次数时,应该会出现其它结果。

实验二实验报告
【实验名称】:进程通信(实验2)
【实验目的】:掌握用邮箱方式进行进程通信的方法,并通过设计实现简单邮箱理解进程通信中的同步问题以及解决该问题的方法。

【实验原理】:邮箱机制类似于日常使用的信箱。

对于用户而言使用起来比较方便,用户只需使用send()向对方邮箱发邮件receive()从自己
邮箱取邮件,send()和receive()的内部操作用户无需关心。

因为邮箱在内存中实现,其空间有大小限制。

其实send()和receive
()的内部实现主要还是要解决生产者与消费者问题。

【实验内容】:进程通信的邮箱方式由操作系统提供形如send()和receive()的系统调用来支持,本实验要求学生首先查找资料了解所选用操作
系统平台上用于进程通信的系统调用具体形式,然后使用该系统调
用编写程序进行进程间的通信,要求程序运行结果可以直观地体现
在界面上。

在此基础上查找所选用操作系统平台上支持信号量机制
的系统调用具体形式,运用生产者与消费者模型设计实现一个简单
的信箱,该信箱需要有创建、发信、收信、撤销等函数,至少能够
支持两个进程互相交换信息,比较自己实现的信箱与操作系统本身
提供的信箱,分析两者之间存在的异同。

【实验要求】:每个同学必须独立完成本实验、提交实验报告、源程序和可执行程序。

实验报告中必须包含背景知识介绍,设计方案,预计的实
验结果,关键代码的分析,调试记录,实际的实验结果,实验结
果分析等内容。

【背景知识介绍】:
1、sembuf数据结构
struct sembuf
{
unsigned short int sem_num; //semaphore number
short int sem_op; //semaphore operation
short int sem_flg; //operation flag
};
sem_num:是相对应的信号量集中的某一个资源,所以其值是一个从0到相应的信号量集的资源总数(ipc_perm.sem_nsems)之间的整数。

sem_op:指明所要执行的操作。

如果其值为正数,该值会加到现有的信号内含值中。

通常用于释放所控资源的使用权;如果sem_op的值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。

通常用于获取资源的使用权;如果sem_op的值为0,则操作将暂时阻塞,直到信号的值变为0。

sem_flg:信号操作标志,可能的选择有两种
IPC_NOWAIT //对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息。

IPC_UNDO //程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。

这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。

2、 semop函数
函数原型:int semop(int semid, struct sembuf *sops, unsigned nsops); 参数说明:
semid:信号集的识别码,可通过semget获取。

sops:指向存储信号操作结构的数组指针。

nsops:信号操作结构的数量,恒大于或等于1。

返回说明:成功执行时,两个系统调用都返回0。

失败返回-1,错误信息保存在errno中。

3、semget函数
函数原型:int semget(key_t key,int nsems,int semflg);
参数说明:
key:关键字值一般是由系统调用ftok()返回的
nsems:指出了一个新的信号量集中应该创建的信号量的个数
semflg:打开和存取操作与参数semflg中的内容相关。

返回说明:如果成功,则返回信号量集的IPC标识符。

如果失败,返回-1,错误信息保存在errno中。

4、semctl函数
函数原型:int semctl(int semid,int semnum,int cmd,union semun arg); 参数说明:
senid:关键字值
semnum:信号量数目
cmd:要操作的具体命令
arg:semnu的一个联合类型的副本。

返回说明:返回值:如果成功,则为一个正数。

如果失败,则为-1。

错误信息保存在errno中。

5、pthread_create函数
函数原型:int pthread_create(pthread_t *restrict tidp,const
pthread_attr_t *restrict attr,void*(*start_rtn)(void*),void *restrict arg);
参数说明:
tidp:指向线程标识符的指针。

attr:用来设置线程属性。

第三个参数是线程运行函数的起始地址。

arg:运行函数的参数。

【设计方案】:采用两个程序并行的方式,打开两个终端,为两个进程都创建一个邮箱。

并且,要求先输入操作命令,使信箱执行哪种操作,以完成两个进程间的邮件通信。

同时,还应采用pv操作,使当邮箱满和空的时候,分别不能执行发送和接收的工作。

【实验预计结果】:A_Receive()和 B_Receive()分别接收B_Send()和 A_Send ()发出的信息,发送的信息和接受的信息应该一样。

【关键代码分析】:
PV操作实现:
int p(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1; // V操作只需将-1改为0。

sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id, &sem_b, 1) == -1)
{
return 0;
}
return 1;
}
A向B发送信息:
void * A_Send(void *arg)
{
int i;
for(i=0;i<10;i++)
{
semaphore_P(sem_idAs); //P操作
semaphore_P(a_mutex_semaphore); //互斥
int number=rand(); //随机数为发送的邮件
printf("A send to B:%d\n",number);
b_buf[b_buf_top]=number;//邮箱B中接收A发送的邮件
b_buf_top+=1;//A向B发送邮件,B的邮件数量加一
semaphore_V(a_mutex_semaphore); //互斥
semaphore_V(sem_idBr);//V操作
sleep(1);
}
}
【调试记录】:pthread库不是Linux系统默认的库,连接时需要使用库libpthread.a, 所以在使用pthread_create创建线程时,在编译中要加-lpthread参数 gcc -w -lpthread semaphore.c
【实验的实际结果】:
yuiuiui@yuiuiui-desktop:- $ gcc -w -o semaphore -lpthread semaphore.c yuiuiui@yuiuiui-desktop:- $ ./semaphore
B send to A:2
A receive from B:2
A send to B:56
B receive from A: 56
B send to A:37
A receive from B:37
A send to B:45
B receive from A: 45 B send to A:97 A receive from B:97
A send to B:145
B receive from A: 145
B send to A:564
A receive from B:564
A send to B:5647
B receive from A: 5647 B send to A:23123
A receive from B:23123
A send to B:asdf
B receive from A: asdf B send to A:rt
A receive from B:rt 【实验结果分析】:
四个线程并发运行, A_Send()和 B_Send()发出信息,同时打印出发出的信息内容; A_Receive()和 B_Receive()分别接收B_Send()和 A_Send()发出的信息,并打印出接受的信息内容。

发出的内容和接收的内容一样,符合时间情况。

实验三实验报告
【实验目的】:掌握磁盘的工作原理和操作系统进行文件管理的原理
【实验原理】:硬盘的MBR:MBR(Main Boot Record),按其字面上的理解即为主引导记录区,位于整个硬盘的0磁道0柱面1扇区。

在总共512字节的主引导扇
区中,MBR只占用了其中的446个字节(偏移0000--偏移01BD),另外的
64个字节(偏移01BE--偏移01FD)交给了DPT(Disk Partition Table硬盘分
区表),最后两个字节"55,AA"(偏移01FE- 偏移01FF)是分区的结束标志。

这个整体构成了硬盘的主引导扇区。

大致的结构如图所示:
硬盘依据分区表中的信息把硬盘划分为最多四个分区(对于扩展分区,可进
一步划分为多个逻辑分区)。

U盘采用类似的方法划分分区。

每个分区或软
盘上可建立独立的文件系统。

下图是FAT文件系统空间分布结构。

【实验内容】:在掌握磁盘的工作原理和操作系统进行文件管理原理的基础上,自行设计实现在磁盘上建立文件系统的软件,该软件应该具有与Format类似的功能,至少支持一种文件系统格式,如FAT、NTFS或EXT2,至少能够对一种媒体进行格式化,如软盘,U盘或硬盘(不得在实验室的机器上进行硬盘格式化的实验)等。

不能直接调用操作系统提供的格式化工具或类似SHFormatDrive()
的高层系统函数实现该软件。

在DOS环境可使用biosdisk()函数完成底层盘操作,在Windows环境可使用WriteFile()函数完成底层盘操作,在Linux环境上可参考format的源代码。

比较自己设计实现的软件与FORMAT,分析存在什么异同。

【实验要求】每个同学必须独立完成本实验、提交实验报告、源程序和可执行程序。

实验报告中必须包含背景知识介绍,设计方案,预计的实验结果,关键代码的分析,调试记录,实际的实验结果,实验结果分析等内容。

背景知识介绍
一个分区或磁盘能作为文件系统使用前,需要初始化,并将记录数据结构写到磁盘上。

这个过程就叫建立文件系统。

大部分linux文件系统种类具有类似的通用结构。

其中心概念是超级块superblock, i节点inode, 数据块data block,目录块directory block, 和间接块indirection block。

超级块包括文件系统的总体信息。

i节点包括除了名字外的一个文件的所有信息,名字与i节点数目一起存在目录中,目录条目包括文件名和文件的i节点数目。

i节点包括几个数据块的数目,用于存储文件的数据。

i节点中只有少量数据块数的空间,如果需要更多,会动态分配指向数据块的指针空间。

这些动态分配的块是间接块;为了找到数据块,这名字指出它必须先找到间接块的号码。

Linux文件系统通常允许在文件中产生孔(hole), 意思是文件系统假装文件中有一个特殊的位置只有0字节,但没有为这文件的这个位置保留实际的磁盘空间。

这对小的二进制文件经常发生,Linux共享库、一些数据库和其他一些特殊情况。

设计方案
1、用一个文件(3)模拟一个物理硬盘, 通过对该文件格式化操作,模拟linux文件系统中的文件操作。

2、将文件划分为四个分区
预计的实验结果
文件会被格式化,原先文件里的内容都会删除,创建新的文件系统。

关键代码的分析
1、i节点结构
struct inode{
struct inode * i_forw;
struct inode *i_back;
char i_flag;
unsigned int i_ino;//磁盘i节点标号
unsigned int i_count;//引用计数
unsigned short di_number;//关联文件数
unsigned short di_mode;//存取权限
unsigned short di_uid;//磁盘i节点用户id
unsigned short di_gid;//磁盘i节点住id
unsigned int di_size;//大小
unsigned int di_addr[NADDR];//物理块号
};
2、目录项结构
struct direct{
char d_name[DIRSIZ];//目录名
unsigned int d_ino;//目录号
};
3、超级块
struct filsys{
unsigned short s_isize;//i节点块块数
unsigned long s_fsize;//数据块块数
unsigned int s_nfree;//空闲块块数
unsigned short s_pfree;//空闲块指针
unsigned int s_free[NICFREE];//空闲块堆栈
unsigned int s_ninode;//空闲i节点数
unsigned short s_pinode;//空闲i节点指针
unsigned int s_inode[NICINOD];//空闲i节点数组
unsigned int s_rinode;//超级块修改标志
char s_fmod;
};
4、函数说明
ifree:释放i节点区函数
bfree:磁盘块释放函数
iget:i节点内容获取函数
iput:i节点内容释放函数
format:格式化函数
调试记录
实际的实验结果
fzu@fzu-desktop:~/OS$ gcc -w -o format format.c
fzu@fzu-desktop:~/OS$ ./format
请输入文件的位置
/home/fzu/OS/3
format succuss
fzu@fzu-desktop:~/OS$
fzu@fzu-desktop:~/OS$ vim 3
在文件3中输入一些内容,运行格式化程序后,文件不再是原来的内容和格式,想要双击打开,但是显示无法打开次文件。

实验结果分析
文件确实被格式化了,但是此时这个文件是二进制文件系统,无法用gedit或其他程序打开,用vim打开后显示上图内容。

相关文档
最新文档