操作系统第三次实验 14281020

实验三 同步问题

实验题目

1)通过fork的方式,产生4个进程P1,P2,P3,P4,每个进程打印输出自己的名字,例如P1输出“I am the process P1”。要求P1最先执行,P2、P3互斥执行,P4最后执行。通过多次测试验证实现是否正确。

操作系统第三次实验 14281020

操作系统第三次实验 14281020操作系统第三次实验 14281020

 

2)火车票余票数ticketCount 初始值为1000,有一个售票线程,一个退票线程,各循环执行多次。添加同步机制,使得结果始终正确。要求多次测试添加同步机制前后的实验效果。(说明:为了更容易产生并发错误,可以在适当的位置增加一些pthread_yield(),放弃CPU,并强制线程频繁切换.

代码如下:(我用pthread_yield(),总是报错,百度了下改用了sched_yield())

操作系统第三次实验 14281020

未添加同步机制时执行 得出的结果是 501/1199/201,在看下面的同步执行结果

操作系统第三次实验 14281020

添加同步机制后多次执行,结果是700/1100/250

操作系统第三次实验 14281020

期间遇到诸多代码问题,包括调用互斥锁mutex出现了 Segmentation fault (core dumped)的报错.

3)一个生产者一个消费者线程同步。设置一个线程共享的缓冲区, char buf[10]。一个线程不断从键盘输入字符到buf,一个线程不断的把buf的内容输出到显示器。要求输出的和输入的字符和顺序完全一致。(在输出线程中,每次输出睡眠一秒钟,然后以不同的速度输入测试输出是否正确)。要求多次测试添加同步机制前后的实验效果。

操作系统第三次实验 14281020

睡眠一秒

操作系统第三次实验 14281020

睡眠10秒

操作系统第三次实验 14281020

也会按顺序把缓存区的输出。

4)进程通信问题。阅读并运行共享内存、管道、消息队列三种机制的代码
参考资料:
https://www.cnblogs.com/Jimmy1988/p/7706980.html
https://www.cnblogs.com/Jimmy1988/p/7699351.html
https://www.cnblogs.com/Jimmy1988/p/7553069.html
实验测试:
a)通过实验测试,验证共享内存的代码中,receiver能否正确读出sender发送的字符串?如果把其中互斥的代码删除,观察实验结果有何不同?如果在发送和接收进程中打印输出共享内存地址,他们是否相同,为什么?
 

操作系统第三次实验 14281020

验证后,发送后可以收到。一次接受一个词组。

以“end”结束共享内存状态。

取出互斥状态的时候操作系统第三次实验 14281020

打印内存地址,如下图,都是4685828

操作系统第三次实验 14281020操作系统第三次实验 14281020

通过查阅资料得知,若开启地址空间随机化ASLR(这里默认是关闭的),则系统内核为共享内存分配的首地址将会不同,这是现代操作系统为了防止缓冲区遭受攻击导致系统崩溃出错的一种机制。

 

b)有名管道和无名管道通信系统调用是否已经实现了同步机制?通过实验验证,发送者和接收者如何同步的。比如,在什么情况下,发送者会阻塞,什么情况下,接收者会阻塞?

1. 无名管道

通过pipe函数创建管道,pipe的函数为pipedes[2]的数组,pipedes[0]用于写数据,pipedes[1]用于读数据。相当于管道的两端,一段负责写数据,一段负责读数据。
pipe管道是半双工的工作模式,某一时刻只能读或者只能写。

操作系统第三次实验 14281020

编译代码并成功运行

操作系统第三次实验 14281020

2. 有名管道
1)    fifo_send函数*

通过access函数,确认fifio文件是否存在,如果ret=0,fifo文件存在,删除FIFO文件。
通过mikfifo函数创建fifo文件。
打开fifo文件,将buffer内容写入fifo文件
输出"write the message ok!",并关闭fifo文件


2)    fifo_receiver函数

通过access函数,确认fifio文件是否存在,如果ret=0,fifo文件存在,删除FIFO文件。
通过mikfifo函数创建fifo文件。
打开fifo文件,并读取内容到buffer变量中,并统计字符数到num变量。
输出结果,并关闭fifo文件。

编译代码并成功运行

操作系统第三次实验 14281020

操作系统第三次实验 14281020

c)消息通信系统调用是否已经实现了同步机制?通过实验验证,发送者和接收者如何同步的。比如,在什么情况下,发送者会阻塞,什么情况下,接收者会阻塞?

本程序主要是实现两个进程通过消息队列发送信息:

  • server:
  1. 等待接收客户端发送的数据,若时间超出600s,则自动exit;
  2. 当收到信息后,打印接收到的数据;并原样的发送给客户端,由客户端显示
  • client:
  1. 启动两个进程(父子进程),父进程用于发送数据,子进程接收由server发送的数据;
  2. 发送数据:由使用者手动输入信息,回车后发送;当写入“end~”后,退出本进程
  3. 接收数据:接收由Server端发送的数据信息,并打印

操作系统第三次实验 14281020

client端发送数据,有sever端接收后打印并原样发回client端。

同pipeline类似,每个消息的最大长度MSGMAX是有上限的,所以消息队列可存放的数据是有限的,适合用于少量的数据传递。消息队列支持双向通信,克服了管道只能承载无格式字节流的缺点,在进程间只有少量数据传输的前提下实现了同步机制。事实上,当消息队列已满时,发送进程将会被阻塞。

 

5)阅读Pintos操作系统,找到并阅读进程上下文切换的代码,说明实现的保存和恢复的上下文内容以及进程切换的工作流程。

进程切换就是从正在运行的进程中收回处理器,然后再使待运行进程来占用处理器。所谓从某个进程收回处理器,实质上就是将此进程存放在处理器的寄存器中的数据暂时存储起来,从而让其他进程使用寄存器。被中止运行进程的中间数据将被保存在进程的私有堆栈中让其他进程来占用处理器,实质上是把某个进程存放在私有堆栈中寄存器的数据(前一次此进程被中止时的数据)再恢复到处理器的寄存器中去,并把待运行进程的断点送入处理器的程序指针,于是待运行进程就开始被处理器运行了,即此进程已占有处理器的使用权了。每个进程都会分到CPU的时间片来运行,当一个进程用完时间片或者被更高优先级的进程抢占后,它会备份到CPU的运行队列中,同时其他进程在CPU上运行。这个进程切换的过程被称作上下文切换。在切换时,一个进程存储在处理器各寄存器中的中间数据叫做进程的上下文,所以进程的切换实质上就是被中止运行进程与待运行进程上下文的切换。在进程未占用处理器时,进程的上下文是存储在进程的私有堆栈中的。