操作系统实验二
更新时间:2023-10-13 01:29:01 阅读量: 综合文库 文档下载
- 操作系统推荐度:
- 相关推荐
实验二 并发与调度
一、实验目的
在本实验中,通过对事件和互斥体对象的了解,来加深对Windows 2000线程同步的理解。通过分析实验程序,了解管理事件对象的API。了解在进程中如何使用事件对象,在进程中如何使用互斥体对象,线程如何通过文件映射对象发送数据。
在Linux Redhat 9.0操作系统平台上,用pipe()创建一个管道文件,然后用fork()创建两个生产进程和两个消费进程,它们之间通过pipe()传递消息。
二、实验环境
硬件环境:计算机一台,局域网环境; 软件环境:Windows 2000 Professional,Linux Redhat 9.0操作系统平台,Visual C++ 6.0
企业版。
三、实验内容和步骤
第一部分:互斥体对象
本程序中显示的类CCountUpDown使用了一个互斥体来保证对两个线程间单一数值的访问。每个线程都企图获得控制权来改变该数值,然后将该数值写入输出流中。创建者实际上创建的是互斥体对象,计数方法执行等待并释放,为的是共同使用互斥体所需的资源 (因而也就是共享资源) 。 利用互斥体保护共享资源
// mutex项目
# include
public:
CCountUpDown(int nAccesses) :
m_hThreadInc(INVALID_HANDLE_VALUE) , m_hThreadDec(INVALID_HANDLE_VALUE) , m_hMutexValue(INVALID_HANDLE_VALUE) , m_nValue(0) ,
m_nAccess(nAccesses) {
m_hMutexValue = :: CreateMutex( NULL, TRUE, NULL) ;
m_hThreadInc = :: CreateThread( NULL, 0, IncThreadProc,
reinterpret_cast
m_hThreadDec = :: CreateThread( NULL, 0, DecThreadProc,
reinterpret_cast
:: ReleaseMutex(m_hMutexValue) ; }
virtual ~CCountUpDown()
{
:: CloseHandle(m_hThreadInc) ; :: CloseHandle(m_hThreadDec) ; :: CloseHandle(m_hMutexValue) ;
}
virtual void WaitForCompletion() {
if (m_hThreadInc != INVALID_HANDLE_VALUE && m_hThreadDec != INVALID_HANDLE_VALUE) {
:: WaitForSingleObject(m_hThreadInc, INFINITE) ; :: WaitForSingleObject(m_hThreadDec, INFINITE) ; } }
protected:
virtual void DoCount(int nStep) {
while (m_nAccess > 0) {
:: WaitForSingleObject(m_hMutexValue, INFINITE) ; m_nValue += nStep;
std :: cout << “thread: ” << :: GetCurrentThreadId() << “value: ” << m_nValue
<< “access: ” << m_nAccess << std :: endl; --m_nAccess; :: Sleep(1000) ; // 使显示速度放慢 :: ReleaseMutex(m_hMutexValue) ; } }
static DWORD WINAPI IncThreadProc(LPVOID lpParam) {
CCountUpDown* pThis =
reinterpret_cast < CCountUpDown* > (lpParam) ; pThis -> DoCount(+1) ; return(0) ; }
static DWORD WINAPI DecThreadProc(LPVOID lpParam) {
CCountUpDown* pThis =
reinterpret_cast
protected:
HANDLE m_hThreadInc; HANDLE m_hThreadDec; HANDLE m_hMutexValue; int m_nValue; int m_nAccess ;
} ;
void main()
{ CCountUpDown ud(50) ; ud.WaitForCompletion() ; }
分析程序的运行结果,可以看到线程 (加和减线程) 的交替执行 (因为Sleep() API允许Windows切换线程) 。在每次运行之后,数值应该返回初始值 (0) ,因为在每次运行之后写入线程在等待队列中变成最后一个,内核保证它在其他线程工作时不会再运行。
1) 请描述运行结果 (如果运行不成功,则可能的原因是什么?) :
____________________________________________________________________ ________________________________________________________________________ 2) 根据运行输出结果,对照分析程序,可以看出程序运行的流程吗?请简单描述: ____________________________________________________________________ ________________________________________________________________________
第二部分 线程通过文件对象发送数据
Windows 2000提供的线程间通讯类内核对象允许同一进程或跨进程的线程之间互相发送信息,包括文件、文件映射、邮件位和命名管道等,其中最常用的是文件和文件映射。这类对象允许一个线程很容易地向同一进程或其他进程中的另一线程发送信息。
演示线程通过文件对象发送数据
# include
static LPCTSTR g_szFileName = “w2kdg.Fileobj.file.data.txt” ; static DWORD WINAPI ThreadProc (LPVOID lpParam) {
LONG nAdd = reinterpret_cast
:: GetTempPath(MAX_PATH, szFullName) ; // 取得路径 :: strcat(szFullName, g_szFileName) ; HANDLE hFile = :: CreateFile( szFullName, // 文件的完全名称 GENERIC_READ | GENERIC_WRITE, // 具有所有的访问权 FILE_SHARE_READ, // 允许其他线程读取 NULL, // 缺省的安全性 OPEN_ALWAYS, // 创建或打开文件 FILE_ATTRIBUTE_NORMAL, // 普通文件 NULL) ; // 无模板文件 if (hFile != INVALID_HANDLE_VALUE) {
LONG nValue(0) ; DWORD dwXfer(0) ; :: ReadFile( hFile, // 要读取的文件 reinterpret_cast
if (dwXfer == sizeof(nValue) ) {
std :: cout << “read: ” << nValue << std :: endl; }
nValue += nAdd;
:: SetFilePointer(hFile, 0, NULL, FILE_BEGIN) ; :: WriteFile( hFile, // 要写入的文件 reinterpret_cast
NULL) ; // 无重叠I/O if (dwXfer == sizeof(nValue) )
{
std :: cout << “write: ”<< nValue << std :: endl; }
:: CloseHandle(hFile) ;
hFile = INVALID_HANDLE_VALUE; }
return(0) ; }
void main() {
for (int nTotal = 100; nTotal > 0; --nTotal)
{
HANDLE hThread = :: CreateThread(
NULL, // 缺省的安全性 0, // 缺省的堆栈 ThreadProc, // 线程函数 reinterpret_cast
NULL) ; // 忽略线程id :: WaitForSingleObject(hThread, INFINITE) ;
:: Sleep(500) ;
:: CloseHandle(hThread) ;
hThread = INVALID_HANDLE_VALUE;
} }
运行结果 (如果运行不成功,则可能的原因是什么?) :
____________________________________________________________________ ________________________________________________________________________ 阅读和分析程序,请回答问题:
1) 程序中启动了多少个单独的读写线程?
____________________________________________________________________ 2) 使用了哪个系统API函数来创建线程例程?
____________________________________________________________________ 3) 文件的读和写操作分别使用了哪个API函数?
____________________________________________________________________ ________________________________________________________________________ 每次运行进程时,都可看到程序中的每个线程从前面的线程中读取数据并将数据增加,文件中的数值连续增加。这个示例是很简单的通讯机制。可将这一示例用作编写自己的文件读/写代码的模板。
请注意程序中写入之前文件指针的重置。重置文件指针是必要的,因为该指针在读取结束时将处于前四个字节之后,同一指针还要用于向文件写入数据。如果函数向该处写入新数值,则下次进程运行时,只能读到原来的数值。那么:
4) 在程序中,重置文件指针使用了哪一个函数?
____________________________________________________________________ 5) 从输出结果,对照分析程序,可以看出程序运行的流程吗?请简单描述:
____________________________________________________________________ ________________________________________________________________________ 第三部分 用pipe()创建一个管道文件,然后用fork()创建两个生产进程和两个消费进程,它们之间通过pipe()传递消息。
fork系统调用 pid=fork();创建一个子进程,子进程是父进程的完整复制,正常返回值为非负整数。对于父进程来说该数大于0,是子进程的编号(pid);对于子进程来说该数为零。正是利用返回值的不同可以决定二者的后续动作。
pipe系统调用 ret_val=pipe(fd); 参数定义为 int fd[2]。创建一个管道文件,返回两个文件描述符fd[0]和fd[1],它们分别用于管道文件的读和写操作。管道文件创建后,可以被fork所创建的子进程共享。
#include “sys/types.h” #include “sys/file.h” #include “unistd.h” char r_buf[4]; char w_buf[4]; int pipe_fd[2];
pid_t pid1,pid2,pid3,pid4; int producer(int id); int consumer(int id);
int main(int argc,char **argv) { if(pipe(pipe_fd)<0)
{ printf(“pipe create error.\\n”); exit(-1); } else {
printf(“pipe is created successfully!\\n”); if((pid1=fork())==0) producer(1); if((pid2=fork())==0) producer(2); if((pid3=fork())==0) consumer(1); if((pid4=fork())==0) consumer(2);} close(pipe_fd[0]); close(pipe_fd[1]); int i,pid,status;
for( i=0;i<4;i++) pid=wait(&status); exit(0);}
int producer(int id)
{ printf(“producer %d is running!\\n”,id); close(pipe_fd[0]); int i=0;
for(i=1;i<10;i++) {
sleep(3);
if(id==1) strcpy(w_buf,”aaa\\0”); else strcpy(w_buf,”bbb\\0”); if(write(pipe_fd[1],w_buf,4)==-1) printf(“write to pipe error\\n”); }
close(pipe_fd[1]); printf(“producer %d is over!\\n”,id); exit(id);}
int consumer(int id) { close(pipe_fd[1]);
printf(“consumer %d is running!\\n”,id); if(id==1) strcpy(w_buf,”ccc\\0”); else strcpy(w_buf,”ddd\\0”); while(1) { sleep(1);
strcpy(r_buf,”eee\\0”);
if(read(pipe_fd[0],r_buf,4)==0) break;
printf(“Consumer %d get %s, while the w_buf is %s\\n”, id,r_buf,w_buf); }
close(pipe_fd[0]);
printf(“consumer %d is over!\\n”,id); exit(id); }
先阅读和分析程序,写出运算结果,并加以解释:
__________________________________________________________________ __________________________________________________________________ __________________________________________________________________ __________________________________________________________________
四、实验总结
请总结一下本次实验的收获、教训和感受,结合课本内容谈一下你对进程间控制的理解。
正在阅读:
操作系统实验二10-13
九寨风情作文500字07-15
我的老师作文400字03-12
建东职业技术学院优秀个人简历07-18
高二1班班规04-04
外汇投机成功17式05-16
2013年基础班儿科学讲义(1)11-15
精美电子报模板09-05
关于提高工资待遇的申请08-09
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- 操作系统
- 实验
- 吴昌硕题画诗(3)
- 2018-2024年中国办公自动化设备市场运行态势报告(目录) - 图文
- 八年级历史上册《难忘九一八》同步练习1 人教新课标版
- 教师推荐阅读书目
- 食堂、宿舍电气施工组织设计方案
- 企业战略管理案例分析张震凯
- 学生外汇市场交易习题集(DOC)
- 英译汉与汉译英
- 招聘财务经理要求汇总
- 湖南省XX7年口腔助理医师:口腔颌面部神经分类模拟试题
- 浅谈会计诚信与职业道德
- 方案预控管理办法
- 高职高专英语教学现状与对策研究
- 使用UC3842设计的CUK降压电路(无PCB电路板)
- 苏教版小学六年级语文上册第3课《把我的心脏带回祖国》教学设计
- 2018年全国卷理科数学十年真题分类汇编 数列
- 读《小学数学与数学思想方法》心得体会
- 中考英语必备:50个重点句型及英汉双语例子
- 某某乡镇小城镇建设汇报材料
- 医学影像学试题