In this exercise you will design the context switch mechanism for a user-level threading system, and then implement it. To get you started, your xv6 has two files user/uthread.c and user/uthread_switch.S, and a rule in the Makefile to build a uthread program. uthread.c contains most of a user-level threading package, and code for three simple test threads. The threading package is missing some of the code to create a thread and to switch between threads.
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.
Some Hints
thread_switch needs to save/restore only the callee-save registers. Why?
You can see the assembly code for uthread in user/uthread.asm, which may be handy for debugging.
void thread_init(void) { // main() is thread 0, which will make the first invocation to // thread_schedule(). It needs a stack so that the first thread_switch() can // save thread 0's state. current_thread = &all_thread[0]; current_thread->state = RUNNING; }
n 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.
Some hints
The numbers you see may differ from this sample output by a factor of two or more, depending on how fast your computer is, whether it has multiple cores, and whether it’s busy doing other things.
ph runs two benchmarks. First it adds lots of keys to the hash table by calling put(), and prints the achieved rate in puts per second. The it fetches keys from the hash table with get(). It prints the number keys that should have been in the hash table as a result of the puts but are missing (zero in this case), and it prints the number of gets per second it achieved.
static voidput(int key, int value) { int i = key % NBUCKET;
// is the key already present? structentry *e =0; for (e = table[i]; e != 0; e = e->next) { if (e->key == key) break; } if(e){ // update the existing key. e->value = value; } else { // the new is new. pthread_mutex_lock(&put_lock); insert(key, value, &table[i], table[i]); pthread_mutex_unlock(&put_lock); }
}
staticstruct entry* get(int key) { int i = key % NBUCKET;
pthread_mutex_lock(&get_lock); structentry *e =0; for (e = table[i]; e != 0; e = e->next) { if (e->key == key) break; } pthread_mutex_unlock(&get_lock);
return e; }
Barrier(moderate)
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.
Some hints
pthread_cond_wait releases the mutex when called, and re-acquires the mutex before returning.
We have given you barrier_init(). Your job is to implement barrier() so that the panic doesn’t occur. We’ve defined struct barrier for you; its fields are for your use.
You have to deal with a succession of barrier calls, each of which we’ll call a round. bstate.round records the current round. You should increment bstate.round each time all threads have reached the barrier.
You have to handle the case in which one thread races around the loop before the others have exited the barrier. In particular, you are re-using the bstate.nthread variable from one round to the next. Make sure that a thread that leaves the barrier and races around the loop doesn’t increase bstate.nthread while a previous round is still using it.
staticvoid barrier() { // YOUR CODE HERE // // Block until all threads have called barrier() and // then increment bstate.round. pthread_mutex_lock(&bstate.barrier_mutex); bstate.nthread++; if (bstate.nthread >= nthread) { bstate.round++; pthread_cond_broadcast(&bstate.barrier_cond); bstate.nthread = 0; } else { pthread_cond_wait(&bstate.barrier_cond, &bstate.barrier_mutex); } pthread_mutex_unlock(&bstate.barrier_mutex);
}
实验总结:
这个实验涉及多个部分:
Multithreading - Uthread: Switching Between Threads