也是借鉴了网上一些实现,勉勉强强将Project1过了,不过感觉代码中还是有些问题的。
alarm测试集
这个测试集要求重新实现timer_sleep()函数,将原来的忙等待改为非忙等待。
思路跟阻塞线程类似:
- 1.为线程增加一个新的状态,表示线程正处在sleep中。
thread.h:在文件靠前添加宏定义:
#define THREAD_SLEEP THREAD_BLOCKED
- 2.在内核中增加一个列表sleep_list,用于存放处于THREAD_SLEEP状态的线程。
thread.c:在文件靠前添加静态变量:
static struct list sleep_list;
- 3.在struct thread结构体中添加两个成员变量,用于保存与THREAD_SLEEP状态相关的信息。
thread.h:修改后的struct thread结构体:
struct thread
{
/* Owned by thread.c. */
tid_t tid; /* Thread identifier. */
enum thread_status status; /* Thread state. */
char name[16]; /* Name (for debugging purposes). */
uint8_t *stack; /* Saved stack pointer. */
int priority; /* Priority. */
struct list_elem allelem; /* List element for all threads list. */
/* Shared between thread.c and synch.c. */
struct list_elem elem; /* List element. */
struct list_elem slpelem;//sleep_list的链表元素
int64_t sleep_ticks;//还需要等待的ticks次数
#ifdef USERPROG
/* Owned by userprog/process.c. */
uint32_t *pagedir; /* Page directory. */
#endif
/* Owned by thread.c. */
unsigned magic; /* Detects stack overflow. */
};
- 4.为了实现非忙等待的timer_sleep(),需要实现几个函数,具体功能下文会解释。
thread.h:在文件靠后添加函数声明:
void thread_sleep(int64_t ticks);
void thread_foreach_sleep (void);
bool thread_less_priority(const struct list_elem *a,const struct list_elem *b,void *aux UNUSED);
- 5.实现thread_sleep()函数,该函数会将当前线程放入sleep_list队列中,并更新线程信息,最后调用schedule()进行新线程调度。该函数会在timer_sleep()中被调用。
thread.c:在文件靠后添加以下代码:
void
thread_sleep(int64_t ticks)
{
enum intr_level old_level=intr_disable();
struct thread *t=thread_current();//获取当前线程
t->sleep_ticks=ticks;//设置当前线程需要等待的ticks次数
list_push_back (&sleep_list, &t->slpelem);//将当前线程放入sleep_list队列中
t->status = THREAD_SLEEP;//更新当前线程的状态为THREAD_SLEEP
schedule ();//进行线程调度,交出cpu,让其他线程继续执行
intr_set_level(old_level);
}
- 6.实现thread_foreach_sleep()函数,该函数会遍历sleep_list队列,并将其中的每个线程的sleep_ticks减1;若某个线程的sleep_ticks为0,即该线程不需要再继续等待,便将该线程从sleep_list队列移至就绪队列中。该函数会在timer_interrupt()中被调用。
thread.c:在文件靠后添加以下代码:
void
thread_foreach_sleep (void)
{
enum intr_level old_level=intr_disable();
struct list_elem *e;
for (e = list_begin (&sleep_list); e != list_end (&sleep_list);
e = list_next (e))//遍历sleep_list中的每一个元素
{
struct thread *t = list_entry (e, struct thread, slpelem);//得到线程结构体
t->sleep_ticks--;//更新sleep_ticks
if(t->sleep_ticks==0)//如果还需等待的ticks为0,即sleep时间到了
{
list_remove(e);//将该线程从sleep_list队列中删除
t->status = THREAD_READY;//将该线程的状态设置为THREAD_READY
list_push_back (&ready_list, &t->elem);//将该线程放入就绪队列中
}
}
intr_set_level(old_level);
}
- 7.实现thread_less_priority()函数,该函数会比较传入线程a和b的优先级,若a的优先级小于b的,则返回真,否则返回假。该函数会在next_thread_to_run中被调用,用来从就绪队列中选择优先级最高的线程。
thread.c:在文件靠后添加一下代码:
bool
thread_less_priority(const struct list_elem *a,const struct list_elem *b,void *aux UNUSED)
{
return list_entry(a,struct thread,elem)->priority<list_entry(b,struct thread,elem)->priority;
}
- 8.修改timer_sleep()函数:一是要对输入参数进行合法性检查,输入参数ticks必须大于0才有意义;二是要将其改为非忙等待,看了上面的内容,其实思路已经很清楚了,只要调用thread_sleep()将当前线程扔到sleep_list队列中就行了。
timer.c:修改后的timer_sleep()函数:
void
timer_sleep (int64_t ticks)
{
if(ticks<=0)
return;
thread_sleep(ticks);
}
- 9.修改timer_interrupt()函数:当每个ticks中断到来时,需要对sleep_list中的线程进行更新,否则sleep中的线程将永远不会被唤醒。
timer.c:修改后的timer_interrupt()函数:
static void
timer_interrupt (struct intr_frame *args UNUSED)
{
ticks++;
thread_foreach_sleep();//增加对sleep_list中线程的更新
thread_tick ();
}
- 10.需要对新加入的sleep_list在系统启动后进行初始化,所以在thread_init函数中添加一行代码。
thread.c:修改后的thread_init()函数:
void
thread_init (void)
{
ASSERT (intr_get_level () == INTR_OFF);
lock_init (&tid_lock);
list_init (&ready_list);
list_init (&all_list);
list_init (&sleep_list);//对sleep_list进行初始化
/* Set up a thread structure for the running thread. */
initial_thread = running_thread ();
init_thread (initial_thread, "main", PRI_DEFAULT);
initial_thread->status = THREAD_RUNNING;
initial_thread->tid = allocate_tid ();
}
- 11.收尾工作,因为project要求在调度下一个进程时,选择优先级最高的来执行,所以需要修改next_thread_to_run()函数。该函数原先选择就绪队列中的第一个线程来执行,现在我们利用库函数中提供的list_max()来选择其中优先级最高的线程。
thread.c:修改后的next_thread_to_run()函数:
static struct thread *
next_thread_to_run (void)
{
struct list_elem *e;
if (list_empty (&ready_list))
return idle_thread;
else
{
e=list_max (&ready_list,&thread_less_priority,NULL);//从前往后找到第一个优先级最高的线程
list_remove(e);//从就绪队列中将选中的线程删去
return list_entry (e, struct thread, elem);
}
}
priority测试集
这个测试集主要是要求实现锁的优先级捐赠,及将cond改为按优先级选择下一线程,并且保证执行中的线程始终是优先级最高的。
因为原先的实现中是将lock视为值为1的信号量来处理的,为了实现优先级捐赠,需要用到其中的等待队列,但这样包裹一层结构体觉得很麻烦,所以对lock做了较大改动。
- 1.为了实现优先级捐赠,我们先考虑struct thread需要增加哪些变量。我们需要记录当前线程的基础优先级,这样当捐赠结束时才能恢复原先的优先级;我们需要记录线程已经持有的锁,这样才能在需要的时候(获得或释放一个锁时),根据这些锁来决定新的捐赠的优先级大小;还需要记录线程正在等待的锁,这样当发生嵌套捐赠时,可以根据这个变量不断向前找到下一个被捐赠对象。
thread.h:修改后的struct thread结构体:
struct thread
{
/* Owned by thread.c. */
tid_t tid; /* Thread identifier. */
enum thread_status status; /* Thread state. */
char name[16]; /* Name (for debugging purposes). */
uint8_t *stack; /* Saved stack pointer. */
int priority; /* Priority. */
struct list_elem allelem;