MIT 6.1810: Multithreading

警告
本文最后更新于 2023-04-18,文中内容可能已过时。

MIT 6.1810 中第六个 lab 的 solution

Multithreading

Your job is to come up with a plan to create threads and save/restore registers to switch between threads, and implement that plan. When you’re done, make grade should say that your solution passes the uthread test.

这个就是抄就行了。

struct thread结构体加一个新元素:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
struct context {
  uint64 ra;
  uint64 sp;

  // callee-saved
  uint64 s0;
  uint64 s1;
  uint64 s2;
  uint64 s3;
  uint64 s4;
  uint64 s5;
  uint64 s6;
  uint64 s7;
  uint64 s8;
  uint64 s9;
  uint64 s10;
  uint64 s11;
};

struct thread {
  char       stack[STACK_SIZE]; /* the thread's stack */
  int        state;             /* FREE, RUNNING, RUNNABLE */
  struct context context;
};

thread_schedule()函数让加的那个部分只需要加个对注释里说的那个函数的引用:

1
thread_switch((uint64)&t->context, (uint64)&next_thread->context);

thread_create()函数在初始化线程的时候需要初始化新加的context这个变量

1
2
3
t->state = RUNNABLE;
t->context.ra = (uint64)func;
t->context.sp = (uint64)t->stack + STACK_SIZE;

至于uthread_switch.S也只需要抄之前在调度那里见过的代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
thread_switch:
	sd ra, 0(a0)
        sd sp, 8(a0)
        sd s0, 16(a0)
        sd s1, 24(a0)
        sd s2, 32(a0)
        sd s3, 40(a0)
        sd s4, 48(a0)
        sd s5, 56(a0)
        sd s6, 64(a0)
        sd s7, 72(a0)
        sd s8, 80(a0)
        sd s9, 88(a0)
        sd s10, 96(a0)
        sd s11, 104(a0)

        ld ra, 0(a1)
        ld sp, 8(a1)
        ld s0, 16(a1)
        ld s1, 24(a1)
        ld s2, 32(a1)
        ld s3, 40(a1)
        ld s4, 48(a1)
        ld s5, 56(a1)
        ld s6, 64(a1)
        ld s7, 72(a1)
        ld s8, 80(a1)
        ld s9, 88(a1)
        ld s10, 96(a1)
        ld s11, 104(a1)
        
        ret

In this assignment you will explore parallel programming with threads and locks using a hash table. You should do this assignment on a real Linux or MacOS computer (not xv6, not qemu) that has multiple cores. Most recent laptops have multicore processors.

全局定义一个lock

1
pthread_mutex_t lock;

main()首先初始化这个lock

1
pthread_mutex_init(&lock, NULL);

然后在put的时候加锁就行了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
static 
void put(int key, int value)
{
  int i = key % NBUCKET;

  // is the key already present?
  struct entry *e = 0;
  for (e = table[i]; e != 0; e = e->next) {
    if (e->key == key)
      break;
  }
  pthread_mutex_lock(&lock);
  if(e){
    // update the existing key.
    e->value = value;
  } else {
    // the new is new.
    insert(key, value, &table[i], table[i]);
  }
  pthread_mutex_unlock(&lock);

}

In this assignment you’ll implement a barrier: a point in an application at which all participating threads must wait until all other participating threads reach that point too. You’ll use pthread condition variables, which are a sequence coordination technique similar to xv6’s sleep and wakeup.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
static void 
barrier()
{
  int tmp = bstate.round;

  pthread_mutex_lock(&bstate.barrier_mutex);
  if(++bstate.nthread != nthread)
    pthread_cond_wait(&bstate.barrier_cond, &bstate.barrier_mutex);
  else
    pthread_cond_broadcast(&bstate.barrier_cond);
  if(bstate.round == tmp){
    bstate.round++;
    bstate.nthread = 0;
  }
  pthread_mutex_unlock(&bstate.barrier_mutex);
}