16281005操作系统实验一
作业题目
一、(系统调用实验)了解系统调用不同的封装形式。
要求
- 参考下列网址中的程序。阅读分别运行用API接口函数getpid()直接调用和汇编中断调用两种方式调用Linux操作系统的同一个系统调用getpid的程序(请问getpid的系统调用号是多少?linux系统调用的中断向量号是多少?)。
- 上机完成习题1.13。
- 阅读pintos操作系统源代码,画出系统调用实现的流程图。
二、(并发实验)根据以下代码完成下面的实验。
要求
- 编译运行该程序(cpu.c),观察输出结果,说明程序功能。
(编译命令: gcc -o cpu cpu.c –Wall)(执行命令:./cpu) - 再次按下面的运行并观察结果:执行命令:./cpu A & ; ./cpu B & ; ./cpu C & ; ./cpu D &程序cpu运行了几次?他们运行的顺序有何特点和规律?请结合操作系统的特征进行解释。
三、(内存分配实验)根据以下代码完成实验。
要求
- 阅读并编译运行该程序(mem.c),观察输出结果,说明程序功能。
(命令: gcc -o mem mem.c –Wall) - 再次按下面的命令运行并观察结果。两个分别运行的程序分配的内存地址是否相同?是否共享同一块物理内存区域?为什么?命令:./mem &; ./mem &
四、(共享的问题)根据以下代码完成实验。
要求
- 阅读并编译运行该程序,观察输出结果,说明程序功能。(编译命令:gcc -o thread thread.c -Wall –pthread)(执行命令1:./thread 1000)
- 尝试其他输入参数并执行,并总结执行结果的有何规律?你能尝试解释它吗?
(例如执行命令2:./thread 100000)(或者其他参数。) - 提示:哪些变量是各个线程共享的,线程并发执行时访问共享变量会不会导致意想不到的问题。
作业解答
一、(系统调用实验)了解系统调用不同的封装形式。
- getpid的系统调用号是0x14
linux系统调用的中断向量号是0x80,两代码执行情况如下:
- 两种调用方式如下。
其中,linux的系统调用使用write函数。Write为 write(int fd, const void *buf, size_t nbyte);此函数有三个参数,第一个参数为1表示为指向控制台输出,第二个参数为输出内容指向内存单元,第三个参数表示写入文件的指定字节数。
通过c语言内嵌会变得形式进行输出打印。其中asm volatile()函数的使用时,第一个参数表示要显示的字符串长度,第二个为输出文件的描述符,第三个为要显示的字符串,第四个为系统调用号。输入int$0x80触发系统中断,之后进行输出,绑定字符串和字符串长度变量。
- pintos操作系统的系统调用的实现如下:
二、(并发实验)根据以下代码完成下面的实验。
-
此程序功能为输出命令行参数中的内容。例如当输入的参数个数为0时(注意代码中设置的条件为不等于2,因为函数的名称在是命令行参数中的第一个,用户参数从第二个算起),则输出提示信息。
-
按照题目要求操作后显示结果如下图
由程序输出我们可以得知,程序输出字母顺序与命令行输入参数的顺序不一致的。
且此输出顺序在不断变化。分析程序运行过程我们可知,在宏观意义上这四个程序是同时运行的,但分析系统内部可知四个程序由cpu交替运行的,他们的优先级相同,所以先开始运行的程序不一定先结束运行,从而导致四个程序在输出信息是,输出结果与输入参数不同,且不唯一。
三、(内存分配实验)根据以下代码完成实验
-
程序运行结果如下
程序运行过程中进行了内存分配并且将对应的内存地址输出打印,将0放入内存的第一个位置,依次进行内存分配和数字的分配位置。 -
程序运行结果如下
本题运行了两个程序进程,从运行结果中我们可以看出,两个独立运行的程序并不共享同一块一块物理地址。这是因为操作系统虚拟化了内存。每个进程访问自己的私有虚拟地址空间,操作系统以某种方式映射到机器的物理内存,同时运行的进程之间并不会互相影响。
四、(共享的问题)根据以下代码完成实验。
-
程序运行结果如下
调用程序时输入的参数为1000。程序内部通过Pthread .create()创建两个线程,每个线程在worker()中运行,实现循环递增,计数区间为1。当两个线程完成时,计数器的最终值为2000。所以此程序功能为当输入参数为N时,输出2N。 -
进行多次尝试后,发现当增大输入的参数,会得到的不为2N的输出结果,如图所示。
分析原因如下:有计数器原理可得,当计数器实现递增过程时,需要三个指令:计数器的值从存储器加载到寄存器中、递增、存储回内存。这就意味着递增的实现需要三个步骤依次执行,并不能同时完成,所以三个指令操作与其他操作之间的执行顺序是不固定的。并且countor、loops这两个全局变量是被这两个线程共享的。当两个的线程一起被调用执行的时候,共享全局变量countor,在编写多线程的程序时,同一个变量可能被多个线程修改,而程序通过该变量同步各个线程。所以当参数变得很大时,就会因为指令调用顺序和参数共享的缘故导致错误。