一种基于线程机制的死锁模拟教学实验设计

来源 :科技创新导报 | 被引量 : 0次 | 上传用户:buyaowenwo123456
下载到本地 , 更方便阅读
声明 : 本文档内容版权归属内容提供方 , 如果您对本文有版权争议 , 可与客服联系进行内容授权或下架
论文部分内容阅读
  摘 要:计算机操作系统课程由于概念抽象,较难理解和掌握,因而课程实验对于加强概念的理解显得尤为重要。死锁是该课程的一个非常核心的概念,本文设计了一个基于windows环境下线程机制的死锁模拟教学实验,程序简单,易于实现和理解。实践表明,该实验在教学过程中收到了良好效果。
  关键词:操作系统死锁; 教学实验线程
  中图分类号: G642文献标识码:A 文章编号:1674-098X(2012)03(c)-0000-00
  
  
  计算机操作系统课程是计算机本科专业的一门专业核心课,也是一门考研课程。该课程由于涉及到操作系统的深层次概念和原理,因而对于大多数学生而言,较难理解和掌握。正由于该课程的重要性,很多高校研究人员对该课程的教学方法进行了深入探讨,如文献[1],[2]。而目前的操作系统实验教材虽然不少[3][4],但很少有设计实验直接对死锁现象进行模拟的。本文基于线程机制利用windows环境下API函数实现了一个死锁现象的构建和模拟实验,算法简单,易于被学生理解,教学中可操作性强。
  
  1 死锁的基本概念
  设系统中存在一组进程(2个或2个以上进程),其中每一个进程都占用了某些资源,而又都在等待其中另一个进程所占用的资源,如果系统无外力作用,这种等待永远不会结束,则称系统出现了“死锁”,或说这组进程处于“死锁”状态。
   死锁是因并发进程竞争资源而引起的一种现象,并发进程对多个资源的共享与竞争有可能导致死锁。死锁可以在2个或多个进程之间发生,也可以在系统全部进程之间产生。死锁是一种与时间有关的错误,在并发系统中,死锁可以在进程通信过程中以及在用信号量作同步工具时,由于P、V操作顺序不当而产生。
   因此,产生死锁的原因是,一方面是由于多进程共享的资源不足而引起竞争资源;另一方面是由于进程在运行过程中推进顺序不合法。
  
  2 实验内容设计
  问题描述:设有一个仓库存有50箱货物,需要请若干搬运工人搬走。本实验通过两个线程模拟完成2个搬运工人合作搬运货物的过程。
  一方面,利用关键代码段(临界区)实现线程同步;另一方面,模拟实现线程死锁。利用线程死锁来让学生体会进程死锁的本质概念。实验采用windows下的Visual C++平台的Console Application进行。
  通过本次实验,可以帮助学生熟悉VC下关键代码段(即临界区),和相关API函数。分析线程同步的参考代码,分析运行结果。理解线程同步的概念。
  实验中,首先给学生提供一段初始程序,该程序可以实现2个搬运工线程正常合作搬运货物的过程。这样,既可以减少学生实验的难度,提高实验效率,又可以让学生将实验的注意力集中到对同步和死锁问题的理解上去。
  然后,要求学生进一步调试和修改代码,并思考以下两个问题:
  ① 如何修改,使得搬运线程1会始终搬运货物,而搬运线程2始终得不到搬运货物的机会?
  ② 如果对本次实验给出的参考代码进行修改,制造线程死锁现象?
  2.1初始程序及分析
  初始程序如下:
  #include
  #include
  DWORD WINAPI FuncProc1(LPVOID
   lpParameter);//thread data
  DWORD WINAPI FuncProc2(LPVOID
   lpParameter);//thread data
  int products=50;//货物总数
  CRITICAL_SECTION csA;
  void main()
  {
  HANDLE hThread1;
   HANDLE hThread2;
   hThread1=CreateThread(NULL,0,FuncProc1,NULL,0,NULL);//创建进程
   hThread2=CreateThread(NULL,0,FuncProc2,NULL,0,NULL);
  CloseHandle(hThread1);
   CloseHandle(hThread2);
  InitializeCriticalSection(&csA);//创建临界区对象
  Sleep(4000);
  DeleteCriticalSection(&csA);//程序退出前释放临界区对象资源
  }
  
  DWORD WINAPI FuncProc1(LPVOID lpParameter)//thread data
  {
  while(TRUE)
  {
  EnterCriticalSection(&csA);//判断能否进临界区
  Sleep(1);
  if(products>0)
  {
   Sleep(1);
   cout<<”thread1 move product:”<   LeaveCriticalSection(&csA);//释放临界区对象
  }
  else
  {
   LeaveCriticalSection(&csA);
   break;
   }
  }
  return 0;
  }
  
  DWORD WINAPI FuncProc2(LPVOID lpParameter)//thread data
  {
  while(TRUE)
  {
  EnterCriticalSection(&csA);
   Sleep(1);
  if(products>0)
  {
  Sleep(1);
  cout<<"thread2 move product:"<  LeaveCriticalSection(&csA);
  }
  else
  {
   LeaveCriticalSection(&csA);
  break;
  }
  }
   return 0;
  }
  程序运行结果及简要分析如下,
  经过编译运行后,输出如下结果:
  thread2 move product:50
  threadl move product:49
  thread2 move product:48
  threadl move product:47
  thread2 move product:46
  threadl move product:45
  ……
  thread2 move product:2
  threadl move product:1
  请按任意键继续. .
  
  临界区被占用的时间一般不允许过长,只要进入临界区的线程还没有离开,其他所有试图进入此临界区的线程都会被挂起而进入到等待状态,并会在一定程度上影响程序的运行性能。尤其需要注意的是不要将等待用户输入或是其他一些外界干预的操作包含到临界区。如果进入了临界区却一直没有释放,同样也会引起其他线程的长时间等待。即,必须确保EnterCriticalSection()语句和与之匹配的LeaveCriticalSection()语句都能够被完整执行到。可以通过添加结构化异常处理代码来确保LeaveCriticalSection()语句的执行。虽然临界区同步速度很快,但却只能用来同步本进程内的线程,而不可用来同步多个进程中的线程。
  2.2 构建死锁现象
  怎样修改这个程序,才有可能使其产生死锁呢?关键在于临界区的个数要多于一个。换句话说,只要临界区数大于1,并且线程数多于1,就有可能出现死锁。
  其源程序代码修改如下:
  DWORD WINAPI FuncProc1(
   LPVOID lpParameter);
  DWORD WINAPI FuncProc2(
   LPVOID lpParameter);
  int products=50;
  CRITICAL_SECTION csA;
  CRITICAL_SECTION csB;
  
  void main()
  {
   HANDLE hThread1;
   HANDLE hThread2;
   hThread1=CreateThread(NULL,0,FuncProc1,NULL,0,NULL);//创建线程
   hThread2=CreateThread(NULL,0,FuncProc2,NULL,0,NULL);
   CloseHandle(hThread1);
   CloseHandle(hThread2);
   InitializeCriticalSection(&csA);//创建临界区对象
  InitializeCriticalSection(&csB);
  Sleep(4000);
  DeleteCriticalSection(&csA);//程序退出前释放临界区对象资源
  }
  DWORD WINAPI FuncProc1(
   LPVOID lpParameter)
  {
   while(TRUE)
   {
   EnterCriticalSection(&csA);//判断能否进入临界区
   Sleep(1);
   if(products>0)
   {EnterCriticalSection(&csB);
   Sleep(1);
   cout<<"threadl move product:"<   LeaveCriticalSection(&csA);//释放临界区对象所有权
   }
   else
   { LeaveCriticalSection(&csA);
   break;
   }
   }
   return 0;
  }
  DWORD WINAPI FuncProc2(
   LPVOID lpParameter)
  {
   while(TRUE)
   {
   EnterCriticalSection(&csA);
   Sleep(1);
   if(products>0)
   {EnterCriticalSection(&csA);
   Sleep(1);
   cout<<"thread2 move product:"<   LeaveCriticalSection(&csB);
   }
   else
   {LeaveCriticalSection(&csA);
   break;
   }
   }
   return 0;
  }
  由此我们再引导学生回顾产生死锁的必要条件:
  ① 互斥使用资源条件;
  ② 占有和等待条件;
  ③ 不剥夺条件;
  ④ 循环等待条件。
  可以发现,两个搬运线程之所以产生死锁,正是满足了以上死锁的必要条件。
  
  3 讨论
  由线程概念扩展到进程概念。当系统中有2个甚至多个临界区,并且多个进程同时共享这些临界区时,进程之间因为资源竞争关系很可能会发生死锁,使死锁发生的几率增大。此时,我们可以通过以下思路来预防死锁,即通过给每个进程所需要的资源(临界区)进行编号,并且让进程在申请这些资源时,采取按序申请的原则(序号从小到大或从大到小)逐一申请,这样,可以在一定程度可以预防死锁,使系统中各程序能正常运行下去。
  这一思想正是操作系统教材中提出的有序资源分配法,由此,我们将死锁的产生、过程和预防办法都进行了简要分析。
  
  4 结语
  本文设计了一个基于线程机制的操作系统课程的死锁模拟教学实验,通过本实验的学习,可以帮助学生达到以下实验效果:
  (1)理解线程的概念;
  (2)熟悉进程、线程同步的概念;
  (3)深刻理解死锁的本质;
  (4)深入理解操作系统对多线程调度的管理;
  (5)深刻理解临界区和互斥的概念。
  并由此举一反三,延伸到进程死锁的概念。经教学实验的实践,学生通过本实验加深了对死锁的概念的理解和掌握,收效良好。
  
  
  参考文献
  [1]马晓慧。操作系统课程教学方法探索[J],计算机教育,2011
  [2]刘晓平,陈欣,李琳,路强,田卫东。面向操作系统课程的“启发—探究式”教学方法初探[J]。计算机教育,2011
  [3]王煜,张明,刘振鹏。操作系统习题解答与实验指导,中国铁道出版社,2004
  
其他文献
文章阐述了南李庄铁矿防治水技术的现状,论述-20m马头门突水的发生、发展及封堵过程,提出了掘砌面预注浆、特殊岩层加倍预注浆、超前探水等防治水技术方法,并指出帷幕注浆是
摘 要:由于受储能电容容量的限制,随着脉冲宽度的增加,脉冲调制器在对微波電子管放电时,会在调制脉冲顶部形成较大的顶部跌落,影响发射机系统输出微波质量,降低雷达系统测距和测速精度。本文提出一种基于LC串联谐振的脉冲调制器顶部跌落补偿方法,并用PSPICE进行仿真,给出详细的仿真结果,验证该补偿方法的有效性。  关键词:雷达 脉冲调制器 宽脉冲顶部跌落补偿 LC串联谐振电路  中图分类号:TP2
随着科学的不断的发展,工程测量领域也出现了一些比较前沿的技术。本文主要对工程测量中的新技术进行研究和探讨。
针对工业工程专业英语教学存在的问题,提出改革工业工程专业英语教学的一些想法,并付诸实践,即在明确工业工程专业英语课程属性的基础上,对教学内容进行补充、整合与更新,设
为了研究横向分布为平顶高斯模式的宽带激光通过硬边光阑系统的光强分布特性,采用衍射积分公式推导了平顶高斯模式宽带激光的每一频率分量在光阑系统中的传输公式,再通过傅里叶