首页 > 代码库 > Pintos Project1的同步问题

Pintos Project1的同步问题

Pintos的官方文档很明显假设这个OS是运行在单cpu上,从sema_up等函数是通过禁止中断来保证原子性和解决竞争问题中也能看到这点。

因为在多cpu上是不能通过禁止中断来解决同步问题,多个线程在多个cpu上仍有可能在临界区改变同一个共享变量。

通过禁止中断是可以解决所有竞争问题,但是可能会带来很多问题:

①如果一个线程陷入死循环,占用了整个cpu,其它线程就不可能获得cpu了。

当然一个线程占用太长时间,对于其它线程来说也不公平。

②中断请求被屏蔽。例如IO设备的读写请求完成后发出的中断信号被屏蔽掉了;时钟中断处理程序运行不了。

③中断解决同步问题效率比较低。与正常指令相比,中断置位和复位要花更长时间。

Pintos实验中也不推荐使用该方法解决同步问题,所以能用信号量、锁、条件变量解决就尽量用,实在不行再采用禁止中断。

当然为了保证原子性,也只能用禁止中断


 

以下是回答DESIGN DOCUMENT中的同步问题:

当多个线程同时调用timer_sleep()时如何避免竞争条件:

使用锁或者禁止中断。

使用前者:

首先增加一个全局变量锁:static struct lock tid_lock;

然后如下:

1   lock_acquire (&tid_lock);              //请求锁
2   struct thread *t = thread_current ();
3   t->wake_ticks = timer_ticks() + ticks;
4   list_insert_ordered (&wait_list, &t->elem, priority_less_func, NULL); //插入队列
5   lock_release (&tid_lock);              //释放锁

当在timer_sleep过程中遇到时钟中断时如何避免竞争条件:

<style>pre.cjk { font-family: "Nimbus Mono L", monospace } p { margin-bottom: 0.1in; line-height: 120% } a:link { }</style>

想想如果遇到时钟中断调度到别的线程有什么后果。

设调用timer_sleep的线程为T1

a.如果线程过多,再调度到T1可能已经花了很多时钟周期了,这时候才开始计时已经很迟了。

b.刚好在thread_block()之前调度到别的线程之后,如果在调度到T1之前调用thread_unblock(T1),会出现问题。

所以一定要保证该函数的原子性,即不可中断。

即:

1   old_level = intr_disable ();  //禁止中断
2   struct thread *t = thread_current ();
3   t->wait_ticks = timer_ticks() + ticks;
4   list_insert_ordered (&wait_list, &t->elem, priority_less_func, NULL);
5   thread_block();  //这个函数调用的前提是禁止中断
6   intr_set_level (old_level);   //恢复到原来状态

综合两个竞争条件的解决方案得出,采用禁止中断方案即可同时解决两个问题。


 

Pintos Project1的同步问题