Multithreading
Uthread:switching between threads
这个实验是在给定的代码基础上实现用户级的线程切换,我们只需要模仿一下 Kernel 中的 Context 即可
(1)定义一下 context
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| struct context { uint64 ra; uint64 sp; uint64 s0; uint64 s1; uint64 s2; uint64 s3; uint64 s4; uint64 s5; uint64 s6; uint64 s7; uint64 s8; uint64 s9; uint64 s10; uint64 s11; };
|
(2)修改一下 thread 结构体
1 2 3 4 5
| struct thread { char stack[STACK_SIZE]; int state; struct context context; };
|
(3)初始化线程的时候像 kernel 中一样初始化一下线程的栈和返回地址,初始的返回地址就是传进来的函数地址
1 2 3 4 5 6 7 8 9 10 11 12
| void thread_create(void (*func)()) { struct thread *t;
for (t = all_thread; t < all_thread + MAX_THREAD; t++) { if (t->state == FREE) break; } t->state = RUNNABLE; t->context.ra = (uint64)func; t->context.sp = (uint64)(t->stack + STACK_SIZE); }
|
thread_schedule 最后调用一下 thread_switch 即可
1 2 3 4 5 6 7
| if (current_thread != next_thread) { next_thread->state = RUNNING; t = current_thread; current_thread = next_thread; thread_switch((uint64)&t->context, (uint64)¤t_thread->context); } else next_thread = 0;
|
Using threads (moderate)
因为哈希表的链表用的是头插法,两个线程同时修改链表的头部*p 导致链表会少一次操作,我们只需要在调用 Insert 前获取对操作链表的锁即可
1 2 3 4 5 6 7 8 9
| if(e){ e->value = value; } else { pthread_mutex_lock(&lock[i]); insert(key, value, &table[i], table[i]); pthread_mutex_unlock(&lock[i]); }
|
barrier
题目是有多个线程,希望实现在每个线程到达barrier这个函数的时候都会被阻塞直到所有线程都到达这个位置
代码里面有个nthread代表到达线程的数量,我们只需要使每个线程到达这个位置的时候将nthread++,在所偶有线程都到达后nthread置为0。然后怎么让它们都阻塞呢,我们需要一个信号量cond,当nthread++之后,锁还没有被释放,我们使用pthread_cond_wait(&cond,&mock)函数让它们都阻塞并把锁释放出来,然后等到ntherad == n的时候激活信号量即可,但是因为激活了信号量之后他们都会持有锁,所有要把锁解开
1 2 3 4 5 6 7 8 9 10 11 12 13
| static void barrier() { pthread_mutex_lock(&bstate.barrier_mutex); bstate.nthread++; if (bstate.nthread == nthread) { bstate.nthread = 0; bstate.round++; pthread_cond_broadcast(&bstate.barrier_cond); } else pthread_cond_wait(&bstate.barrier_cond, &bstate.barrier_mutex); pthread_mutex_unlock(&bstate.barrier_mutex); }
|