操作系统原理实验报告.docx
- 文档编号:12383159
- 上传时间:2023-04-18
- 格式:DOCX
- 页数:112
- 大小:1.04MB
操作系统原理实验报告.docx
《操作系统原理实验报告.docx》由会员分享,可在线阅读,更多相关《操作系统原理实验报告.docx(112页珍藏版)》请在冰豆网上搜索。
操作系统原理实验报告
《操作系统原理》
实验报告
班级:
:
学号:
指导老师:
目录:
实验题目:
实验一线程创建与撤销
完成人:
XXX
报告日期:
2018年3月31日
一、实验容简要描述
(1)熟悉VC++、VisualStudio开发环境。
(2)使用相关函数创建和撤销线程。
(3)在一个进程中创建3个线程,名字分别为threada、threadb、threadc。
threada输出“helloworld!
”。
threadb输出“Mynameis…”。
threadc输出“Pleasewait…”,然后sleep5秒钟,接着输出“Iwakeup”。
二、程序设计
1、设计思路
该函数创建一个在调用进程的地址空间中执行的线程。
2、主要数据结构
HANDLECreateThread(
LPSECURITY_ATTRIBUTESlpThreadAttributes,
DWORDdwStackSize,
LPTHREAD_START_ROUTINElpStartAddress,
LPVOIDlpParameter,
DWORDdwCreationFlags,
LPDWORDlpThreadId
);
VOIDExitThread(DWORDdwExitCode);
VOIDSleep(DWORDdwMilliseconds);
VOIDSleep(DWORDdwMilliseconds);
三、实验结果
1、基本数据
lpThreadAttributes:
指向一个SECURITY_ATTRIBUTES结构,该结构决定了返回的句柄是否可被子进程继承。
若lpThreadAttributes为NULL,则句柄不能被继承。
在WindowsNT中该结构的lpSecurityDescriptor成员定义了新进程的安全性描述符。
若lpThreadAttributes为NULL,则线程获得一个默认的安全性描述符。
dwStackSize:
定义原始堆栈提交时的大小(按字节计)。
系统将该值舍入为最近的页。
若该值为0,或小于默认时提交的大小,默认情况是使用与调用线程同样的大小。
更多的信息,请看ThreadStackSize。
lpStartAddress:
指向一个LPTHREAD_START_ROUTlNE类型的应用定义的函数,该线程执行此函数。
该指针还表示溃程进程中线程的起始地址。
该函数必须存在于远程进程中。
lpParameter:
定义一个传递给该迸程的32位值。
dwCreationFIags:
定义控制进程创建的附加标志。
若定义了CREATE_SUSPENDED标志,线程创建时处于挂起状态,并且直到ResumeThread函数调用时d能运行。
若该值为0,则该线程在创建后立即执行。
lpThreadId:
指向一个32位值,它接收该线程的标识符。
2.
源程序代码行数
完成该实验投入的时间(小时数)
与其他同学讨论次数
31
1
1
3、测试结果分析
四、实验体会
1、实验体会和收获
深入理解了线程与进程的概念,熟悉了在Windows环境下何时使用进程,何时使用线程,怎么创建和撤销线程。
五、源代码
#include
#include
usingnamespacestd;
DWORDWINAPIta(LPVOIDargv)
{
cout<<"HelloWorld!
\n";
}
DWORDWINAPItb(LPVOIDargv)
{
cout<<"我的名字:
婷\n";
cout<<"我的学号:
141340209\n";
}
DWORDWINAPItc(LPVOIDargv)
{
cout<<"Pleasewait...\n";
Sleep(5000);
cout<<"Iwakeup.\n";
}
intmain()
{
HANDLEthreada,threadb,threadc;
DWORDTEST;
threada=CreateThread(NULL,0,ta,NULL,0,0);
threadb=CreateThread(0,0,tb,0,0,0);
threadc=CreateThread(0,0,tc,0,0,0);
ExitThread(TEST);
ExitThread(TEST);
ExitThread(TEST);
return0;
}
实验题目:
实验二线程同步
完成人:
XXX
报告日期:
2018年4月7日
一、实验容简要描述
1)在程序中使用CreateSemaphore(NULL,0,1,”SemaphoreName1”)创建一个名为SemaphoreName1的信号量,其初值为0。
2)使用OpenSemaphore(SYNCHRONIZE|SEMAPHORE__MODIFY_STA
TE,NULL,”SemaphoreName1”)打开该信号量。
3)创建一个子线程,主线程创建子线程后调WaitForSingleObject(hHandle,
INFINITE),这里等待时间设置为INFINITE表示要一直等待下去,直到该信号量被唤醒为止。
4)子线程sleep5秒钟,然后输出“Iamover.”结束,调用ReleaseSemaphore(hHandle1,1,NULL)释放信号量,使信号量的值加1。
二、程序设计
1、设计思路
A)等待一个对象
WaitForSingleObjects函数决定等待条件是否被满足。
如果等待条件并没有被满足,调用线程进人一个高效的等待状态,当等待满足条件时占用非常少的处理器时间。
在运行前,一个等待函数修改同步对象类型的状态。
修改仅发生在引起函数返回的对象身上。
例如,信号的计数减l。
WaitForSingleObject函数能等待的对象包括:
Changenotification(改变通告);Consoleinput(控制台输入);Event(事件);Job(作业);Mutex(互斥对象);Process(进程);Semaphore(信号量);Thread(线程);Waitabletimer(可等待定时器)。
当使用等待函数或代码直接或间接创建窗口时,一定要小心。
如果一个线程创建了任何窗口,它必须处理进程消息。
消息广播被发送到系统的所有窗口。
一个线程用没有超时的等待函数也许会引起系统死锁。
间接创建窗口的两个例子是DDE和COMCoInitialize。
因此,如果用户有一个创建窗口的线程,用MsgWaitForMultipleObjects或MsgWaitForMultipleObjectsEx函数,而不要用
SignalObjectAndWait函数。
B)等待多个对象
WaiForMultipleObjects函数当下列条件之一满足时返回:
(1)任意一个或全部指定对象处于信号态;
(2)超时间隔已过。
C)创建信号量
如果成功就传回一个handle,否则传回NULL。
不论哪一种情况,GetLastError都会传回一个合理的结果。
如果指定的Semaphore名称已经存在,则函数还是成功的,GetLastError会传回ERROR_ALREADY_EXISTS。
D)打开信号量
为现有的一个已命名信号机对象创建一个新句柄。
E)增加信号量的值
该函数将指定信号对象的计数增加一个指定的值。
2、主要数据结构
DWORDWaitForSingleObject(HANDLEhHandle,DWORDdwMilliseconds);
DWORDWaitForMultipleObjects(
DWORDnCount,
CONSTHANDLE*lpHandles,
BOOLfWaitAll,
DWORDdwMilliSeconds
)
HANDLECreateSemaphore(
LPSECURITY_ATTRIBUTESlpAttributes,
LONGlInitialCount,
LONGlMaximumCount,
LPCTSTRlpName
);
HANDLEOpenSemaphore(
DWORDdwDesiredAccess,//访问标志
BOOLbInheritHandle,//继承标志
LPCTSTRlpName//信号量名
);
BOOLReleaseSemaphore(
HANDLEhSemaphore,
LONGlReleaseCount,
LPLONGlpPreviousCount
)
三、实验结果
1、基本数据
源程序代码行数
完成该实验投入的时间(小时数)
与其他同学讨论次数
61
2
1
2、测试结果分析
四、实验体会
1、实验体会和收获
进一步认识了线程同步的实质,学会使用信号量控制线程间的同步。
五、源代码
#include
#include
#include
staticHANDLEhThread1;//子进程的句柄,作为主线程的局部变量也行
staticHANDLEhHandle1=NULL;//信号量的句柄,全局变量
voidfunc();//子线程的声明
intmain(intargc,TCHAR*argv[],TCHAR*envp[])
{
intnRetCode=0;
DWORDdwThreadID1;
DWORDdRes,err;
hHandle1=CreateSemaphore(NULL,0,1,"SemaphoreName1");//创建一个信号量
if(hHandle1==NULL)printf("SemaphoreCreateFail!
\n");
elseprintf("SemaphoreCreateSuccess!
\n");
hHandle1=OpenSemaphore(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE,NULL,"SemaphoreName1");
if(hHandle1==NULL)printf("SemaphoreOpenFail!
\n");
elseprintf("SemaphoreOpenSuccess!
\n");
hThread1=CreateThread((LPSECURITY_ATTRIBUTES)NULL,0,
(LPTHREAD_START_ROUTINE)func,
(LPVOID)NULL,
0,&dwThreadID1);//创建子线程
if(hThread1==NULL)printf("Thread1createFail!
\n");
elseprintf("Thread1createSuccess!
\n");
dRes=WaitForSingleObject(hHandle1,INFINITE);//主线程等待子线程结束
err=GetLastError();
printf("WaitForSingleObjecterr=%d\n",err);
if(dRes==WAIT_TIMEOUT)
printf("TIMEOUT!
dRes=%d\n",dRes);
elseif(dRes==WAIT_OBJECT_0)
printf("WAIT_OBJECT!
dRes=%d\n",dRes);
elseif(dRes==WAIT_ABANDONED)
printf("WAIT_ABANDONED!
dRes=%d\n",dRes);
elseprintf("dRes=%d\n",dRes);
CloseHandle(hThread1);
CloseHandle(hHandle1);
printf("我的名字:
婷\n");
printf("我的学号:
141340209\n");
ExitThread(0);
returnnRetCode;
}
//实现子线程
voidfunc()
{
BOOLrc;
DWORDerr;
printf("NowInThread!
\n");
printf("Iamover.\n");
rc=ReleaseSemaphore(hHandle1,1,NULL);//子线程唤醒主线程
err=GetLastError();
printf("ReleaseSemaphoreerr=%d\n",err);
if(rc==0)printf("SemaphoreReleaseFail!
\n");
elseprintf("SemaphoreReleaseSuccess!
rc=%d\n",rc);
}
实验题目:
实验三线程互斥
完成人:
XXX
报告日期:
2018年4月14日
三、实验容简要描述
完成两个子线程之间的互斥。
在主线程中使用系统调用CreateThread()创建两个子线程,并使两个子线程互斥的使用全局变量count。
四、程序设计
3、设计思路
a.使用临界区对象(Criticalsection)
CriticalSectionObject,Asegmentofcodethatisnotreentrantandthereforedoesnotsupportconcurrentaccessbymultiplethreads.Often,acriticalsectionobjectisusedtoprotectsharedresources。
通过定义在数据段中的一个CRITICAL_SECTION结构实现。
CRITICAL_SECTIONmyCritical;
并且在任何线程使用此临界区对象之前必须对它进行初始化。
voidInitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
之后,任何线程访问临界区中数据的时候,必须首先调用EnterCriticalSection函数,申请进入临界区(又叫关键代码段,使用共享资源的任何代码都必须封装在此)。
在同一时间,Windows只允许一个线程进入临界区。
所以在申请的时候,如果有另一个线程在临界区的话,EnterCriticalSection函数会一直等待下去,直到其他线程离开临界区才返回。
EnterCriticalSection函数用法如下:
voidEnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
当操作完成的时候,还要将临界区交还给Windows,以便其他线程可以申请使用。
这个工作由LeaveCriticalSection函数来完成。
voidLeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
当程序不再使用临界区对象的时候,必须使用DeleteCriticalSection函数将它删除。
voidDeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
b.使用互斥锁(Interlocked)
提供一种手段来保证值的递增(减)能够以原子操作方式来进行,也就是不中断地进行。
LONGInterlockedIncrement(LPLONGlpAddend);//增一操作
LONGInterlockedDecrement(LPLONGlpAddend);//减一操作
LONGInterlockedExchangeAdd(
PLONGAddend,//pointertotheaddend
LONGIncrement//incrementvalue
);//增减任意值
4、主要数据结构
voidInitializeCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
voidEnterCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
voidLeaveCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
voidDeleteCriticalSection(LPCRITICAL_SECTIONlpCriticalSection);
LONGInterlockedIncrement(LPLONGlpAddend);//增一操作
LONGInterlockedDecrement(LPLONGlpAddend);//减一操作
LONGInterlockedExchangeAdd(
PLONGAddend,//pointertotheaddend
LONGIncrement//incrementvalue
三、实验结果
1、基本数据
源程序代码行数
完成该实验投入的时间(小时数)
与其他同学讨论次数
68
2
0
2.测试结果分析
四、实验体会
1、实验体会和收获
熟练了Windows系统环境下线程的创建与撤销,熟悉了Windows系统提供的线程互斥API,使用Windows系统提供的线程互斥API解决实际问题。
五、源代码
#include
#include
#include
staticintcount=5;//共享变量
staticHANDLEh1,h2;//两个子进程的句柄变量
LPCRITICAL_SECTIONhCriticalSection;//定义指向临界区对象的地址指针
CRITICAL_SECTIONCritical;//定义临界区
voidfunc1();//线程函数的定义不符合WIN32格式,后面CreateThread函数中
voidfunc2();//要附加强制类型转换
//主线程的实现
intmain(intargc,TCHAR*argv[],TCHAR*envp[])
{
intnRetCode=0;
DWORDdwThreadID1,dwThreadID2;
hCriticalSection=&Critical;//将指向临界区的对象的指针指向临界区
InitializeCriticalSection(hCriticalSection);//初始化临界区
//创建子线程func1
h1=CreateThread((LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)func1,
(LPVOID)NULL,
0,&dwThreadID1);
if(h1==NULL)printf("Thread1createFail!
\n");
elseprintf("Thread1createsuccess!
\n");
//创建子线程func2
h2=CreateThread((LPSECURITY_ATTRIBUTES)NULL,
0,
(LPTHREAD_START_ROUTINE)func2,
(LPVOID)NULL,
0,&dwThreadID2);
if(h2==NULL)printf("Thread2createFail!
\n");
elseprintf("Thread2createsuccess!
\n");
Sleep(1000);
CloseHandle(h1);
CloseHandle(h2);
DeleteCriticalSection(hCriticalSection);//删除临界区
ExitThread(0);
returnnRetCode;
}//主线程结束
//子线程func2的实现
voidfunc2()
{
intr2;
EnterCriticalSection(hCriticalSection);//进入临界区
r2=count;
Sleep(100);
r2=r2+1;
count=r2;
printf("countinfunc2=%d\n",count);
LeaveCriticalSection(hCriticalSection);//退出临界区
}
//子线程func1的实现
voidfunc1()
{
intr1;
EnterCriticalSection(hCriticalSection);//进入临界区
r1=count;
Sleep(500);
r1=r1+1;
count=r1;
printf("countinfunc1=%d\n",count);
LeaveCriticalSection(hCriticalSection);//退出临界区
}
实验题目:
实验四进程通信
完成人:
XXX
报告日期:
2018年4月21日
五、实验容简要描述
1)利用命名管道的相关知识及函数,分别编写服务器进程和客户端进程程序。
2)要求服务器进程和客户端进程程序能够通过互相传送数据。
3)当服务器进程和客户端进程中的任何一端输入“end”时,结束会话。
六、程序设计
5、设计思路
(1)建立命名管道
(2)连接命名管道
(3)拆除命名管道的连接
(4)客户端进程连接服务器已建立的命名管道
(5)客户端进程等待命名管道
6、主要数据结构
HandleCreateNamedPipe(LPCTSTRlpName,……);
BOOLConnectNamedPipe(HANDLEhNamePipe,OVERLAPPEDlpOverlapped);
BOOLDisconnectNamedPipe(LonghNamedPipe);
BOOLCallNamedPipe(StringlpNamedPipeName,//欲打开管道的名称
lpInBufferAny,//要写入管道的数据的存缓冲区
nInBufferSizeLong,//存缓冲区中的字符数量
lpOutBufferAny,//指定一个存缓冲区,用于装载从管道中读出的数据
nOutBufferSizeLong,//指定一个长整数变量,用于装载来自管道的数据
lpBytesReadLong,//指定从管道中读出的字节数
nTimeOutLong,//管道是否可用及超时设置
);
BOOLWaitNamedPipe(LPCTSTRlpNamedPipeName,DWORDnTimeOut);
三、实验结果
测试结果
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 操作系统 原理 实验 报告