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]; /* the thread's stack */
int state;
struct context context; /* FREE, RUNNING, RUNNABLE */
};

(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) {         /* switch threads?  */
next_thread->state = RUNNING;
t = current_thread;
current_thread = next_thread;
thread_switch((uint64)&t->context, (uint64)&current_thread->context);
} else
next_thread = 0;

Using threads (moderate)

因为哈希表的链表用的是头插法,两个线程同时修改链表的头部*p 导致链表会少一次操作,我们只需要在调用 Insert 前获取对操作链表的锁即可

1
2
3
4
5
6
7
8
9
if(e){
// update the existing key.
e->value = value;
} else {
// the new is new.
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);
}