MIT6.828_HW9_barriers

MIT6.828_HW9_barriers

在这个任务中,我们使用由pthread库提供的条件变量来实现barrier。barrier 是一个应用程序点,必须所有线程到达这个点才能继续执行。条件变量是一种类似于xv6的 sleep 和 wakeup 的序列协调技术。

下载源码,编译执行。

$ gcc -g -O2 -pthread barrier.c
$ ./a.out 2
pthread_cond_wait(&cond, &mutex);  // go to sleep on cond, releasing lock mutex
pthread_cond_broadcast(&cond);     // wake up every thread sleeping on cond

pthread_cond_wait releases the mutex when called, and re-acquires the mutex before returning. 其需要一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait()

barrier_init已经实现了,我们还需要实现barrier(),以致于不会再发生 panic。

有两个问题会使我们的任务变得复杂:

  • 必须处理一连串的 barrier call ,我们称之为一轮。bstate.round records the current round. You should increase bstate.round when each round starts.
  • 必须处理一个线程在其他线程退出 barrier 之前进行下一轮循环的情况。 In particular, you are re-using bstate.nthread 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.

实现过程

互斥量实现线程互斥,条件量用来实现线程同步。

在主函数里创建了 nthread(参数传入的) 个线程。

for(i = 0; i < nthread; i++) {
    assert(pthread_create(&tha[i], NULL, thread, (void *) i) == 0);
}

for(i = 0; i < nthread; i++) {
    assert(pthread_join(tha[i], &value) == 0);
}

使用pthread_cond_wait方式如下,为了避免由于线程并发执行所引起的资源竞争,所以要让每个线程互斥的访问公有资源,但是细心一下就会发现,如果while或者if判断的时候,不满足线程的执行条件,那么线程便会调用pthread_cond_wait阻塞自己,但是它持有的锁怎么办呢,如果他不归还操作系统,那么其他线程将会无法访问公有资源。pthread_cond_wait详解

    pthread _mutex_lock(&mutex)
    
    while或if(线程执行的条件是否成立)
          pthread_cond_wait(&cond, &mutex);
    线程执行
    pthread_mutex_unlock(&mutex);

每个线程循环 20000 次, 检查 i 是否等于 bstate.round, 实际就是不能让其他线程修改 bstate.round,应该是需要线程同步。pthread_join()函数会一直阻塞调用线程,直到指定的线程tid终止。英语是硬伤,一开始没理解清楚这个 HW 到底在表达什么,写出了以下代码(barrier()根本没改),也能 pass。按照我这种写法,是每个线程轮流执行了(失去了多线程的意义),后来发现是需要每个线程同步执行一次round++

static void *
thread(void *xa)
{
  long n = (long) xa;
  long delay;
  int i;

  pthread_mutex_lock(&bstate.barrier_mutex );
  if (bstate.round != 0) {
	  pthread_cond_wait(&bstate.barrier_cond, &bstate.barrier_mutex);
  }
  for (i = 0; i < 20000; i++) {
    int t = bstate.round;
	// The assert triggers, because one thread leaves the barrier before the other thread has reached the barrier. 
    assert (i == t);
	printf("thread %d\n", i);
    barrier();
    usleep(random() % 100);
  }
  bstate.round = 0;
  pthread_cond_broadcast(&bstate.barrier_cond);
  pthread_mutex_unlock(&bstate.barrier_mutex );
}

实际代码,修改barrier(),如下。

static void 
barrier()
{
  pthread_mutex_lock(&bstate.barrier_mutex );
  bstate.nthread++;
  if (bstate.nthread == nthread) {
	// 最后一个进程进入 执行 round++, 再唤醒其他进程。
	bstate.round++;
	bstate.nthread = 0;
	// 唤醒其他进程
    pthread_cond_broadcast(&bstate.barrier_cond);  
  } 
  else {
	  pthread_cond_wait( &bstate.barrier_cond, &bstate.barrier_mutex);
  }
  
  pthread_mutex_unlock(&bstate.barrier_mutex );
}

Questions

  1. 错误代码中pthread_cond_broadcast注释掉还是能 pass, why?

因为按照代码逻辑,线程根本不会进入 wait 里。第一个线程直接进入,第二个线程会卡在 lock_mutex上。

你可能感兴趣的:(MIT6.828操作系统,MIT6.828,HW9,barriers,XV6)