操作系统学习笔记: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函数中加锁和解锁:
这样,再编译运行时,就可以避免丢失了:
具体的代码如下:
我的水平还不够将这个代码详细的讲解清楚,希望比我更了解XV6的大神们能指正我的错误,再次感谢其他帮助我学习XV6的博主们,你们的博客means a lot to me!
决定开始写博客的原因是:之前学习操作系统课的时候,每周老师布置的都是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_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); | |
} |
相关文章推荐
- 2017 6.824学习笔记 Lecture 2: RPC and threads
- 用S60操作系统SDK开发NOKIA手机应用程序-学习笔记(1)
- 用S60操作系统SDK开发NOKIA手机应用程序-学习笔记(1)
- 计算机学习笔记--操作系统
- Pro visual c++/cli and .net 2.0 platform2 学习笔记(4 本书简介)
- 学习笔记-PPP and PPPoE基本概念
- Pro visual c++/cli and .net 2.0 platform2 学习笔记(10 第四章 高级C++/CLI)
- Partner Link Types, Partner Links, and Endpoint References(学习笔记)
- Java核心思想学习笔记002(Static Fields and Methods)
- Pro visual c++/cli and .net 2.0 platform2 学习笔记(8第三章 面向对象的C++/CLI===1)
- 用S60操作系统SDK开发NOKIA手机应用程序-学习笔记(2)
- 扬扬的J2EE学习笔记(三)Components and Roles组件和角色
- SWT下实现Drag and Drop(DND)学习笔记(写作中...)
- VxWorks 学习笔记-IO and File System
- 用S60操作系统SDK开发NOKIA手机应用程序-学习笔记(3)
- PHP and Web Services 学习笔记
- PHP and Web Services 学习笔记
- Lua入门系列----pil学习笔记之Type and Values (2)
- Pro visual c++/cli and .net 2.0 platform2(学习笔记2 目录)
- 操作系统学习笔记(一) > 操作系统概论