操作系统课程设计
实验报告书
20##-06-30
目 录
一、课程设计任务划分... 1
(一)课程内容... 2
(二)算法... 2
(三)算法基本原理... 2
三、基本思路... 4
(一)变量... 4
(二)所用函数... 5
(三)流程图... 9
四、调试及实验结果... 14
五、个人体会... 15
一、课程设计任务划分
二、基本原理
(一)课程内容
编程序模拟车站售票厅内进程同步问题,售票厅任何时刻最多可容纳20名购票者进入,否则需要在外面等待。每个购票者可看成一个进程。
(二)算法
信号量与P,V操作
(三)算法基本原理
生产者-消费者问题是一个经典的线程同步问题,该问题最早由Dijkstra提出,用以演示他提出的信号量机制。在同一个线程地址空间内执行的两个线程。生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。
多个生产/消费者在有界缓冲上操作。它利用N个字节的共享内存作为有界循环缓冲区,利用写一字符模拟放一个产品,利用读一字符模拟消费一个产品。当缓冲区空时消费者应阻塞睡眠,而当缓冲区满时生产者应当阻塞睡眠。一旦缓冲区中有空单元,生产者线程就向空单元中入写字符,并报告写的内容和位置。一旦缓冲区中有未读过的字符,消费者线程就从该单元中读出字符,并报告读取位置。生产者不能向同一单元中连续写两次以上相同的字符,消费者也不能从同一单元中连续读两次以上相同的字符。
因此售票员与乘客也可转化为生产者与消费者的问题,第一步:确定进程间的关系。售票厅是各进程共享的公有资源,当售票厅中多于20名购票者时,厅外的购票者需要在外面等待。所以进程间是互斥的关系。第二步:确定信号量及其值。只有一个公有资源:售票厅,所以设置一个信号量s。售票厅最多容纳20个进程,即可用资源实体数为20,s的初值就设为20。
实现:begin
s:semaphore;
s:=20;
cobegin
process PI(I=1,2,……)
begin P(s);
进入售票厅;
购票;
退出;
V(s);
end;
coend
当购票者进入售票厅前要执行P(s)操作,执行后若s大于或等于零,说明售票厅的人数还未满可进入。执行后若s小于零,则说明售票厅的人数已满不能进入。这个实现中同时最多允许20个进程进入售票厅购票,其余进程只能等待。
三、基本思路
(一)变量
#define N 2 // 乘客或售票员的数目
#define M 20 // 售票厅大小
int in = 0; // 售票员售票的位置
int out = 0; // 乘客买票的位置
int buff[M] = {0}; // 售票厅初始化为0, 开始时没有售票员
sem_t empty_sem; // 同步信号量, 当满了时阻止售票员售票
sem_t full_sem; // 同步信号量, 当没售票员时阻止乘客买票
pthread_mutex_t mutex; // 互斥信号量, 一次只有一个线程访问缓冲
int conductor_id = 0; //售票员id
int passenger_id = 0; //乘客id
(二)所用函数
1. void print() 打印售票厅情况
2. void *conductor () 售票员方法
3. void *passenger () 乘客方法
4. int main() 主方法
5. sem_wait()
函数原形:
int sem_wait(sem_t *sem);
参数:
sem 指向信号灯的指针
返回值:
若成功则返回0,否则返回-1。
我们能用sem_wait来申请共享资源,sem_wait函数能测试所指定信号灯的值,如果该值大于0,那就将他减1并即时返回。我们就能使用申请来的 共享资源了。如果该值等于0,调用线程就被进入睡眠状态,直到该值变为大于0,这时再将他减1,函数随后返回。sem_wait操作必须是原子的。
6. sem_post()
挂出共享资源
函数原形:
int sem_post(sem_t *sem);
参数:
sem 指向信号灯的指针
返回值:
若成功则返回0,否则返回-1。
当一个线程使用完某个信号灯时,他应该调用sem_post来告诉系统申请的资源已用完。本函数和sem_wait函数的功能正好相反,他把所指定的信号灯的值加1,然后唤醒正在等待该信号灯值变为正数的任意线程。
7. sem_init()
初始化信号等
函数原形:
int sem_init(sem_t *sem,int shared,unsigned int value);
参数:
sem 指向信号灯的指针
shared 作用范围
value 信号灯初始值
返回值:
若成功则返回0,否则返回-1。
基于内存的信号灯是由sem_init初始化的。sem参数指向必须由应用程序分配的sem_t变量。如果shared为0,那么待初始化的信号灯是在同 一进程的各个线程共享的,否则该信号灯是在进程间共享的。当shared为零时,该信号灯必须存放在即将使用它的所有进程都能访问的某种类型的共享内存 中。
8 pthread_mutex_init(&mutex, NUL
互斥锁的初始化
函数原型:
int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
函数作用:
pthread_mutex_init() 函数是以动态方式创建互斥锁的,参数attr指定了新建互斥锁的属性。如果参数attr为空,则使用默认的互斥锁属性,默认属性为快速互斥锁 。互斥锁的属性在创建锁的时候指定,在LinuxThreads实现中仅有一个锁类型属性,不同的锁类型在试图对一个已经被锁定的互斥锁加锁时表现不同。
9. pthread_create()
创建线程函数
函数原型:
int pthread_create(pthread_t*restrict tidp,const pthread_attr_t *restrict_attr,void*(*start_rtn)(void*),void *restrict arg);
参数
第一个参数为指向线程标识符的指针。
第二个参数用来设置线程属性。
第三个参数是线程运行函数的起始地址。
最后一个参数是运行函数的参数。
返回值
若成功则返回0,否则返回出错编号
返回成功时,由tidp指向的内存单元被设置为新创建线程的线程ID。attr参数用于制定各种不同的线程属性。新创建的线程从start_rtn函数的地址开始运行,该函数只有一个万能指针参数arg,如果需要向start_rtn函数传递的参数不止一个,那么需要把这些参数放到一个结构中,然后把这个结构的地址作为arg的参数传入。
(三)流程图
A、主函数
B、统计线程
C、生产者线程
D、消费者线程
四、调试及实验结果
实验结果:
五、个人体会
给出设计文档和调试编码的感受,或对原理知识的理解。(100字以上)
由于时间有限,本次设计完成的并不是很完美,下面从以下几点来说明本次课程设计的个人体会:
1.本次课程设计中做的比较好的地方:
做的好的地方就是在于对题目意思的正确理解,以及在此基础上的模型设计。最开始一看题目的时候有点不知道如何着手,只是模糊地知道是怎么回事,能够在思想上想清楚具体的运转过程,参照教科书之后,学会了怎样用P,V原语操作。然后最关键的就是怎样用程序表现这个过程,最后我想出来的方法就是通过乘客上下车的过程来表现,我觉得这样是最好的体现方式。
2.做得不太好的地方,以及以后如何改正:
做得不太好的地方就是不能把自己所学的C知识和本次课程设计的相关知识很好的结合起来,以至于没有很好的表达出本次课程设计的细节。在以后的过程中,我会运用本次课程设计中所学的知识,以及思考问题的方式和方法,争取能够发扬优点,尽量克服不细心,不严谨等缺点。
3.从本次设计中得到的收获(在编写,调试,执行过程中的经验和教训):
通过本次课程设计,我学会了综合运用所学相关知识的能力,动手能力以及独立思考问题的能力。下面具体的收一个边学程序是遇到的困难,首先就是如何把想法变为做法的问题,最开始一拿到题目,我就觉得无从下手,因为我的阅历,不知道如何把这样一个问题变成程序,变成能够让人一目了然的东西,于是,我就先写下了p,v操作的实现过程,因为这个对我来说简单一些,然后,在此基础之上,就好办了,结果最后用了2个函数就解决问题了,所以,我觉得有时候思考问题不要太死脑筋,换一个角度的话,也许会更好,说不定就能达到事半功倍的效果,还有就是,想问题要想明白,想透彻,不能是懂非懂,模模糊糊,想透彻之后再去思考下一步问题,这样办事效率会更高。
第二篇:操作系统课程设计-文件管理实验报告
操作系统课程实验报告
2013~2014年度 第1学期
院系:
学号:
姓名:
任课教师: 成绩评定:
实验一题目:文件管理
完成日期:年 月 日
1、实验目的
了解文件管理的功能和任务,理解文件系统组成和特点,熟悉文件系统的访问和操作。实验要求用高级语言编写和调试一个简单的模拟文件管理程序。加深理解有关盘块的分配与回收、目录管理等的具体实施策略。
2.、实验内容
模拟一个资源管理器进行文件操作,包括建立和删除目录、建立和删除文件等基本文件操作。建立相应的数据结构(如:位示图等),模拟盘块管理。可以参照图6界面进行设计。
3、算法设计
1)、定义主面板MainFrame,布局好各个控件,并初始化
/*
* 往node节点下添加一个子节点obj;
*/
publicvoid addChild(Object obj, DefaultMutableTreeNode node) {
if (obj != null && node != null) {
DefaultMutableTreeNode temp = new DefaultMutableTreeNode(obj);
if (node.getAllowsChildren())
node.add(temp);
if (!((String) obj).equals("A:\\") && ((String) obj).length() <= 3)// 防止读取A软驱,会出现异常;用于初始用的;
addChildren(cmd.listAll((String) obj), temp);
}
}
/*
* 在node节点下添加数组children;
*/
publicvoid addChildren(String[] children, DefaultMutableTreeNode node) {
if (children != null && node != null) {
for (int i = 0; i < children.length; i++) {
addChild(children[i], node);
}
}
}
/*
* 对树的节点进行预提取;
*/
publicvoid addPrefetchChildren(String path, DefaultMutableTreeNode node) {
addChildren(cmd.listDirectory(path), node);
}
/*
* 对路径路径进行连接;(已经获得了所有的整个路径,需要量转化)
*/
public String toFilePath(String str) {
// 先去掉头尾的[];
String pa = str.substring(1, str.length() - 1);
String[] temp = pa.split(", ");
String path = "";
for (int i = 1; i < temp.length; i++) {
if (!path.endsWith("\\") && !path.equals(""))// 不为空是为去根节点;
path += "\\";
path += temp[i];
}
return path;
}
public String toPFilePath(String str) {
// 先去掉头尾的[];
String pa = str.substring(1, str.length() - 1);
String[] temp = pa.split(", ");
String path = "";
for (int i = 1; i < temp.length - 1; i++) {
if (!path.endsWith("\\") && !path.equals(""))// 不为空是为去根节点;
path += "\\";
path += temp[i];
}
return path;
}
publicclass ExpandListener implements TreeWillExpandListener {
/*
* 树展开及收缩监听;
*/
private MainFrame mainFrame = null;
public ExpandListener(MainFrame mainFrame) {
this.mainFrame = mainFrame;
}
publicvoid treeWillExpand(TreeExpansionEvent event) {
// 对节点的路径进行转化
String path = toFilePath(event.getPath().toString());
TreePath treePath = event.getPath();
DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath
.getLastPathComponent();
// System.out.println("所展开节点的路径:" + path);
// System.out.println(treePath);
if (node.getDepth() < 2) {
Enumeration children = node.children();
String filePath = "";
while (children.hasMoreElements()) {
DefaultMutableTreeNode temp = (DefaultMutableTreeNode) children
.nextElement();
filePath = "";
filePath = path;
if (!filePath.endsWith("\\"))
filePath += "\\";
filePath += temp.toString();
// System.out.println("temp=" +filePath);
mainFrame.addPrefetchChildren(filePath, temp);
}
}
}
2)、添加功能“添加文件(夹)addframe()”、“修改文件(夹)mvframe()”
publicvoid addframe() {
JFrame addFrame = new JFrame();
JLabel jlbl = new JLabel("请输入要添加的文件(夹)名:");
addrs = new JLabel("");
addrs.setBounds(180, 10, 100, 25);
jlbl.setBounds(10, 10, 170, 25);
addfile = new JTextField();
addfile.setBounds(10, 40, 260, 25);
btnaddf = new JButton("添加文件");
btnaddd = new JButton("添加文件夹");
btnaddf.setBounds(20, 80, 100, 25);
btnaddd.setBounds(160, 80, 100, 25);
btnaddf.addActionListener(this);
btnaddd.addActionListener(this);
addFrame.add(jlbl);
addFrame.add(addrs);
addFrame.add(addfile);
addFrame.add(btnaddf);
addFrame.add(btnaddd);
addFrame.setBounds(400, 350, 300, 150);
addFrame.setTitle("添加文件(夹)");
addFrame.setLayout(null);
addFrame.setVisible(true);
}
publicvoid mvframe() {
JFrame mvFrame = new JFrame();
JLabel jlbl = new JLabel("请输入修改后的文件名:");
mvrs = new JLabel("");
mvrs.setBounds(160, 10, 140, 25);
jlbl.setBounds(10, 10, 170, 25);
mvfile = new JTextField();
mvfile.setBounds(10, 40, 260, 25);
btnmvf = new JButton("修改文件名");
btnmvd = new JButton(" 修改文件夹名");
btnmvf.setBounds(10, 80, 120, 25);
btnmvd.setBounds(150, 80, 120, 25);
btnmvf.addActionListener(this);
btnmvd.addActionListener(this);
mvFrame.add(jlbl);
mvFrame.add(mvrs);
mvFrame.add(mvfile);
mvFrame.add(btnmvf);
mvFrame.add(btnmvd);
mvFrame.setBounds(400, 350, 300, 150);
mvFrame.setTitle("修改文件(夹)名");
mvFrame.setLayout(null);
mvFrame.setVisible(true);
}
}
3)显示文件
* 显示系统中的所有盘符;
public String[] ListDisks() {
File roots[] = File.listRoots();// 根盘符;
String disks[] = new String[roots.length];
for (int i = 0; i < roots.length; i++) {
disks[i] = roots[i].toString();
}
return disks;
}
* 获得路径path下的文件;
public String[] listAll(String path) {
try {
File f = new File(path);
String[] fileName;
String tmp = null;
mainFrame.fileshow.setText(null);
mainFrame.filestyle.setText(null);
if (f.isDirectory()) {
fileName = f.list();
// System.out.println("共有" + fileName.length + "个文件");
for (int i = 0; i < fileName.length; i++) {
mainFrame.fileshow.append(fileName[i] + '\n');
tmp = path + '\\' + fileName[i];
// System.out.println(tmp);
if (listDirectory(tmp) != null) {
mainFrame.filestyle.append("文件夹\n");
} else {
mainFrame.filestyle.append("文件\n");
}
}
return fileName;
} elseif (f.isFile()) {
System.out.println("这是一个文件");
returnnull;
} else {
// System.out.println(path);
returnnull;
}
} catch (Exception e) {
returnnull;
}
}
public String[] listDirectory(String path) {
File f = new File(path);
String[] fileName;
if (f.isDirectory()) {
fileName = f.list();
return fileName;
} else {
// System.out.println(path + "是文件");
returnnull;
}
}
* 进行md操作;md <目录名> 功能: 创建新目录
publicvoid md(String directory) {
if (!mainFrame.currentPath.equals("")) {
String temp = mainFrame.currentPath + "\\" + directory;
File newFile = new File(temp);
if (!newFile.exists()) {
try {
if (newFile.isDirectory() == false) {
newFile.mkdirs();
System.out.println("文件夹创建成功!");
} else {
System.out.println("文件夹创建出错!");
}
} catch (Exception e) {
System.out.println("出错信息:" + e.getMessage());
}
} else {
System.out.println("文件夹已经存在");
}
}
}
* 进行rd操作;rd <目录名> 功能: 删除目录;
publicvoid del() {
String temp = mainFrame.currentPath;
File file = new File(temp);
if (file.exists()) {
if (file.delete()) {
mainFrame.fileshow.setText("文件(夹)删除成功!");
} else {
mainFrame.fileshow.setText("文件(夹)删除操作出错!");
}
} else {
mainFrame.fileshow.setText("文件(夹)不存在");
}
}
/*
* 进行edit操作:edit <文件名> 功能: 新建文件
*/
publicvoid edit(String file) {
if (!mainFrame.currentPath.equals("")) {
String temp = mainFrame.currentPath + "\\" + file;
File newFile = new File(temp);
if (newFile.exists()) {
mainFrame.addrs.setText("文件已经存在!");
System.out.println("文件已经存在!");
} else {
try {
newFile.createNewFile();
mainFrame.addrs.setText("文件创建成功!");
System.out.println("文件创建成功!");
} catch (Exception e) {
System.out.println("文件创建失败:" + e.getMessage());
}
}
}
}
publicvoid mvf(String file){
if (!mainFrame.PPath.equals("")) {
String temp = mainFrame.PPath + "\\" + file;
File newFile = new File(mainFrame.currentPath);
if (newFile.exists()) {
if(newFile.renameTo(new File(temp))==true){
mainFrame.mvrs.setText("修改文件名成功!");
}else{
mainFrame.mvrs.setText("存在同名文件!");
}
}
}
}
publicvoid mvd(String dir){
if (!mainFrame.PPath.equals("")) {
String temp = mainFrame.PPath + "\\" + dir;
File newFile = new File(mainFrame.currentPath);
if (newFile.exists()) {
if(newFile.renameTo(new File(temp))==true){
mainFrame.mvrs.setText("修改文件夹名成功!");
}else{
mainFrame.mvrs.setText("存在同名文件夹!");
}
}
}
}
}
4、运行与测试
运行时,弹出主界面
双击文件盘C
在E盘路径添加文件夹操作系统,再添加文件操作系统
如果文件已存在会显示
可以更改文件名称
删除文件,不过有个BUG,要文件一层层删,才可以删除。
可以显示目录路径
5、总结与心得
我们每天都在用文件系统,已经习惯了有文件路径寻找的方便,每次找文件时,感觉好容易,可实际去设计这个程序时,却很难。用树形结构图去设计,要有较好的全局思想,而且一些节点的分配。在设计此系统时,发觉自己对文件系统理解得不够透彻。不知道如何来具体设计这个实验,后来耐心回到本学期学习的课本内容上,再次翻看了大二第一学期所学的数据结构的书,才觉悟对文件系统的理解,总而言之,操作系统的设计,不仅提升了自己的程序设计及编写技巧,更大大地加深了对操作系统的文件管理的了解。