您的位置:首页 > 运维架构 > Linux

操作系统学习笔记:Threads and Locking

2016-11-18 21:46 309 查看
操作系统学习笔记1: Threads and Locking

决定开始写博客的原因是:之前学习操作系统课的时候,每周老师布置的都是MIT的公开作业。因为刚开始学习XV6的时候学习的都是其他人的博客,但是那个博主貌似做到homework5之后就不再继续写了。

这里是我看的博主的网站链接:http://blog.csdn.net/column/details/xv6-jos.html

很感激那位博主的宝贵经验,让我前几周的XV6学习能这么快的入门。所以我也希望继续那位博主的工作,把我通过每周的作业学习到的知识分享给学习XV6的freshman们,希望能对学弟学妹们有所帮助。

-------------------------------------------------------------------------------------------------------------------------------------------------------------
一。首先是对题目的分析: https://pdos.csail.mit.edu/6.828/2016/homework/lock.html(原网址)。
本次作业主要讲的是并行作业,以及并行作业中互斥锁(P,V问题)的相关知识。
1.将ph.c文件下载下来,放到Linux的文件夹里。
2.用terminal编译,并运行:$ gcc -g -O2 ph.c -pthread
$ ./a.out 2
我们会发现结果中显示了:
  
这表示ph.c的代码有问题(错误代表的意思之后再说),而作业就需要我们找到这个错误的原因,然后加以修改。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
二。阅读ph.c,然后理解意思(我只把这个代码的意义大概的描述一下,具体的内容需要自己阅读,这是学习XV6非常重要的一个过程)
代码首先创建了10000个小的node,用每一个node(在代码中名字是entry)来表示一个线程(这里涉及C++链表的内容),然后通过平均分配的方法来把这些线程分配给各个进程。
put函数用来将每一个线程加入链表。然后将这个node的对应信息记录到哈希表:struct entry *table[NBUCKET]中。
get函数通过反哈希的方式得到一个node(也就是一个线程)。同时这也表示这次线程的结束。

这样不断通过put 和get来实现并行程序。
产生错误的原因:当我们在使用put函数的时候,不小心造成两个新的node同时插入链表时(也就是同时使用内存),我们的哈希表只能记录下其中的一个表头,而失去了另外一个node的表头,所以造成了get的时候丢失了node。
为了避免这样的错误产生,我们仅仅需要在put的时候加入互斥锁即可:

 
  
    首先在开始处定义一个五个互斥锁:
pthread_mutex_t bucket_locks[NBUCKET];

    
 然后在put函数中加锁和解锁:

 
pthread_mutex_lock(&bucket_locks[i]);
insert(key, value, &table[i], table[i]);
 pthread_mutex_unlock(&bucket_locks[i]);
这样,再编译运行时,就可以避免丢失了:



具体的代码如下:

 
 #include<stdlib.h>#include<unistd.h>
 #include <stdio.h>
 #include <assert.h>
 #include <pthread.h>
 #include <sys/time.h>
  
 #define SOL
 #define NBUCKET 5
 #define NKEYS 100000
  
 struct entry {
 int key;
 int value;
 struct entry *next;
 };
 struct entry *table[NBUCKET];
 int keys[NKEYS];
 pthread_mutex_t bucket_locks[NBUCKET];
 int nthread = 1;
 volatile int done;
  
 double
 now()
 {
 struct timeval tv;
 gettimeofday(&tv, 0);
 return tv.tv_sec + tv.tv_usec /1000000.0;
 }
  
 static void
 print(void)
 {
 int i;
 struct entry *e;
 for (i = 0; i < NBUCKET; i++) {
 printf("%d:", i);
 for (e = table[i]; e != 0; e = e->next) {
 printf("%d", e->key);
 }
 printf("\n");
 }
 }
  
 static void
 insert(int key,int value,struct entry **p, struct entry *n)
 {
 struct entry *e = malloc(sizeof(struct entry));
 e->key = key;
 e->value = value;
 e->next = n;
 *p = e;
 }
  
 static
 void put(int key, int value)
 {
 int i = key % NBUCKET;
 pthread_mutex_lock(&bucket_locks[i]);
 insert(key, value, &table[i], table[i]);
 pthread_mutex_unlock(&bucket_locks[i]);
 }
  
 static struct entry*
 get(int key)
 {
 struct entry *e = 0;
 for (e = table[key % NBUCKET]; e !=0; e = e->next) {
 if (e->key == key) break;
 }
 return e;
 }
  
 static void *
 thread(void *xa)
 {
 long n = (long) xa;// thread number
 int i;
 int b = NKEYS/nthread; // number of keys 'assigned' to this thread
 int k = 0;
 double t1, t0;
  
 // printf("b = %d\n", b);
 t0 = now();
 for (i = 0; i < b; i++) {
 // printf("%d: put %d\n", n, b*n+i);
 // Note that the value for each key is the same, namely
 // the thread number
 put(keys[b*n + i], n);
 }
 t1 = now();
 printf("%ld: put time =%f\n", n, t1-t0);
  
 // Should use pthread_barrier, but MacOS doesn't support it ...
 __sync_fetch_and_add(&done,1);
 // This will only unlock when all threads are done
 while (done < nthread) ;
  
 t0 = now();
 for (i = 0; i < NKEYS; i++) {
 struct entry *e = get(keys[i]);
 if (e == 0) k++;
 }
 t1 = now();
 printf("%ld: lookup time =%f\n", n, t1-t0);
 printf("%ld:%d keys missing\n", n, k);
 return NULL;
 }
  
 int
 main(int argc,char *argv[])
 {
 pthread_t *tha;
 void *value;
 long i;
 double t1, t0;
  
 if (argc < 2) {
 fprintf(stderr, "%s:%s nthread\n", argv[0], argv[0]);
 exit(-1);
 }
 nthread = atoi(argv[1]);
 tha = malloc(sizeof(pthread_t) * nthread);
 srandom(0);
 assert(NKEYS % nthread ==0);
 for (i = 0; i < NKEYS; i++) {
 keys[i] = random();
 }
  
 for (i = 0; i < NBUCKET; i++) {
 pthread_mutex_init(&bucket_locks[i],NULL);
 }
  
 t0 = now();
 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);
 }
 t1 = now();
 printf("completion time =%f\n", t1-t0);
 }
我的水平还不够将这个代码详细的讲解清楚,希望比我更了解XV6的大神们能指正我的错误,再次感谢其他帮助我学习XV6的博主们,你们的博客means a lot to me!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息