实 验 3 : Synchronization Using
Semaphores
实验 5:Extendable Files
实验 6,7,8:实现系统调用 Exec
实验 9:设计并实现具有优先级的线程
调度策略
实验 10: 具有二级索引的文件系统
实验 11:用户空间的虚拟内存管理
计算机科学与技术学院实验报告:3
实验题目:信号量同步问题
日期:2010-11-10
姓名:
实验目的:
在本次实验中,通过使用信号量,在原有的程序框架的基础上添加关键代码实
现生产者/消费者同步问题。从而深入理解 Nachos 的信号量的使用以及实现,
生产者/消费者问题是如何用信号量实现的以及
在 Nachos 中是如何创建线程,实现多线程。
硬件环境:
软件环境:
Linux
实验步骤:
1.首先初始化三个信号量,代码如下:
mutex = new Semaphore("mutux",1);信号量初始化为 1,才能起到加锁功能
nfull = new Semaphore("full",0);nfull 的大小在生产者没生产前为 0
nempty = new Semaphore("empty",BUFF_SIZE);nempty 的大小应该为 buffer 的
大小
2. 首 先 考 虑 生 产 者 进 程 , 首 先 要 查 看 buffer 是 否 有 空 , nempty->P();if
nempty>0,nempty=nempty -1,当对缓冲区操作时必须要加锁:mutex->P();加
锁.
然后向 ring 中放入 message 信息,其次还要解锁 mutex->V();解锁.最后通知消
费者 buffer 有新信息, nfull->V();nfull=nfull+1;具体实现代码如下:
3. 考虑消费者进程,像生产者进程一样,查看 buffer 中是否有信息
nfull->P();if nfull>0,nfull-1;取消息时也要上锁,即:mutex->P();加锁.
然后从 ring buffer 中取出信息;其次 mutex->V();解锁;最后通知生产者
bufferr 有空 nempty->V();nempty=nempty+1,具体代码如下:
4. 创建线程生成一个生产者的代码:
producers[i] = new Thread(prod_names[i]);
producers[i] -> Fork(Producer,i);
4. 创建线程生成一个消费者的代码:
producers[i] = new Thread(prod_names[i]);
producers[i] -> Fork(Producer,i);
关键代码:
void
Producer(_int which)
{
int num;
slot *message = new slot(0,0);
for (num = 0; num < N_MESSG ; num++) {
//这是消息创建的代码
message->thread_id=which;
message->value=num;
//p,v 操作
nempty->P();
mutex->P();
ring->Put(message);
//p,v 操作
mutex->V();
nfull->V();
}
}
void
Consumer(_int which)
{
char str[MAXLEN];
char fname[LINELEN];
int fd;
slot *message = new slot(0,0);
sprintf(fname, "tmp_%d", which);
// create a file. Note that this is a UNIX system call.
if ( (fd = creat(fname, 0600) ) == -1)
{
perror("creat: file create failed");
Exit(1);
}
for (; ; ) {
// p,v,操作
nfull->P();
mutex->P();
ring->Get(message);
// p,v,操作
mutex->V();
nempty->V();
// form a string to record the message
sprintf(str,"producer id --> %d; Message number --> %d;\n",
message->thread_id,
message->value);
//把信息写入文件
if ( write(fd, str, strlen(str)) == -1 ) {
perror("write: write failed");
Exit(1);
}
}
}
//----------------------------------------------------------------------
// ProdCons
// 初始化信号量以及需要的生产者消费者线程
//----------------------------------------------------------------------
void
ProdCons()
{
int i;
DEBUG('t', "Entering ProdCons");
// 初始化信号量,包括一个访问互斥信号量,初值为 1;
//一个nempty信号量,初值为缓冲区的大小
//一个nfull的信号量,初值为 0
mutex=new Semaphore("mutex",1);
nempty=new Semaphore("nempty",BUFF_SIZE);
nfull=new Semaphore("nfull",0);
// 新建一个缓冲区
ring=new Ring(BUFF_SIZE+1);
// create and fork N_PROD of producer threads
for (i=0; i < N_PROD; i++)
{
// this statemet is to form a string to be used as the name for
// produder i.
sprintf(prod_names[i], "producer_%d", i);
// 创建生产者线程
producers[i]=new Thread(prod_names[i]);
producers[i]->Fork(Producer,i);
};
// create and fork N_CONS of consumer threads
for (i=0; i < N_CONS; i++)
{
// this statemet is to form a string to be used as the name for
// consumer i.
sprintf(cons_names[i], "consumer_%d", i);
//创建消费者线程
consumers[i]=new Thread(cons_names[i]);
consumers[i]->Fork(Consumer,i);
};
}
调试记录:
在源代码中 exit(0)没有大写,调试过程发现了这个问题改正,
在使用 Linux 系统调用写入文件时,有一个头文件没有引入,因而需要修改
#include
#include "copyright.h"
#include "system.h"
#include
#include
而且对于新添加的头文件的方法其中源文件使用的一个方法是废弃的,所以改
成相应的方法 write(fd, str, strlen(str)),
实验结果:
生成两个文件分别代表两个消费者取得的产品的记录。
文件 tmp_0
producer id --> 0; Message number --> 3;
文件 tmp_1
producer id --> 0; Message number --> 0;
producer id --> 1; Message number --> 0;
producer id --> 1; Message number --> 1;
producer id --> 0; Message number --> 1;
producer id --> 0; Message number --> 2;
producer id --> 1; Message number --> 2;
producer id --> 1; Message number --> 3;
分析结果:
从实验结果中可以看出,两个消费者取得的产品的顺序和生成者生产的顺序是
一致的。结果正确。
(实验所在目录:home/lu/csc2404/nachos-3.4/code/lab3)
结论分析与体会:
在本次实验中,实现生产者/消费者同步问题,通过使用信号量,即 Nachos 提
供的系统调用,进一步理解 Nachos 的信号量的使用以及实现
同时,学会在 Nachos 中是如何创建线程,实现多线程,理解了多线程的问题。
计算机科学与技术学院实验报告:5
实验题目:扩展 Nachos 的文件系统
日期:2010-11-10
Email:
实验目的:
Nachos 的文件系统的文件的大小是不可扩展的:文件被创建后,文件的大小就不能再改变。
本次实验的目的即是设计扩展 Nachos 的文件系统,使得文件的大小是可以被扩展的。
这样就可以实现在一个文件尾部或者中间追加文件。
硬件环境:
软件环境:
Linux 操作系统,Nachos 操作系统
实验步骤:
1, 了解 Nachos 文件系统的结构,为一级目录结构,
其中目录结构以及目录的使用记录保存在文件中。使用 BitMap 来获取空闲的扇区号。
class DirectoryEntry {
public:
bool inUse;
// Is this directory entry in use?
int sector;
// Location on disk to find the
//
FileHeader for this file
char name[FileNameMaxLen + 1];
// Text name for file, with +1 for
// the trailing '\0'
};
这个是 DirectoryEntry 类,也就是目录项。
Directory::Directory(int size)
{
table = new DirectoryEntry[size];
tableSize = size;
for (int i = 0; i < tableSize; i++)
table[i].inUse = FALSE;
}
这个是目录类,也就是一级目录结构的定义。
bool
Directory::Add(char *name, int newSector)
{
if (FindIndex(name) != -1)
return FALSE;
for (int i = 0; i < tableSize; i++)
if (!table[i].inUse) {
table[i].inUse = TRUE;
strncpy(table[i].name, name, FileNameMaxLen);
table[i].sector = newSector;
return TRUE;
}
return FALSE;
// no space.
Fix when we have extensible files.
}
这个是添加一个目录项的方法,当创建一个新文件的时候使用。
bool
FileSystem::Create(char *name, int initialSize)
这个是创建一个新的文件,其中主要工作是新建一个 FileHeader,
作为一个目录项中保存的 int sector;
FileHeader,即文件头,中保存了这个文件的大小,所占的扇区的数目,
以及所占用的全部的扇区号。即:
int numBytes;
int numSectors;
int dataSectors[NumDirect];
// Number of bytes in the file
// Number of data sectors in the file
// Disk sector numbers for each data
// block in the file
因此,为了实现对文件的追加工作,首先对 FileHeader 类里面加入新的方法
bool AppSectors(BitMap *freeMap, int fileSize);,为了改变一个文件的文件头的大小。