高级程序设计期末大作业重庆科技学院.docx
- 文档编号:13940382
- 上传时间:2023-06-19
- 格式:DOCX
- 页数:14
- 大小:32.11KB
高级程序设计期末大作业重庆科技学院.docx
《高级程序设计期末大作业重庆科技学院.docx》由会员分享,可在线阅读,更多相关《高级程序设计期末大作业重庆科技学院.docx(14页珍藏版)》请在冰点文库上搜索。
高级程序设计期末大作业重庆科技学院
重庆科技学院
《高级系统程序设计》大作业
专业班级:
计科2012-3
学号:
2012442084
姓名:
赵弈胰
成绩:
目录
题目一3
1)完成端口对象和套接字之间的连接意味着什么?
如何连接?
什么是面向连接的套接字,请详细描素。
3
2)多线程程序设计中为什么要使用线程同步策略?
常见的线程同步对象有哪些,其具体特点是什么?
(173)3
3)并行编程有多进程和多线程的方法,请结合课本例程grepMP和grepMT,给出多进程应用和多线程应用的特点。
(126、152)4
4)请编程举例说明WindowsNT6.X中的线程池的特点和使用方法。
5
5)请给出设计一个Windows服务例程的过程。
(293)6
题目二7
1.同步异步方式各自的特点7
2异步方式四种实现方式7
1)触发设备内核对象7
2)触发事件内核对象8
3)可提醒I/O9
4)I/O完成端口10
题目一
1)完成端口对象和套接字之间的连接意味着什么?
如何连接?
什么是面向连接的套接字,请详细描素。
答:
完成端口充分利用Windows内核来进行IO的调度,它提供了一种机制来使用几个线程“公平”的处理来自于多个客户端的输入/输出。
完成端口和WindowsSocket结合可以开发出支持大量连接的网络服务程序。
完成端口与套接字连接后就意味着完成端口对象可以在套接字对象上投递重叠I/O请求处理,实现异步通信。
连接方式:
a.调用CreateIoCompletionPort()函数创建一个完成端口,并返回其句柄;b.根据系统中有多少个处理器,就建立多少个工作者线程,这几个线程是专门用来和客户端进行通信的;
c.启动一个线程接收连入的Socket连接;
d.当有客户端连入时,调用CreateIoCompletionPort()函数把新连入的Socket与当前的完成端口绑定。
面向连接的套接字:
用于实现面向连接的协议。
面向连接套接字在建立连接或接收连接请求前,需要使用WSPBind()函数将套接字绑定到本地地址上或隐式的调用WSPConnect()函数。
即面向连接套接字是需要维护链接的,其结构类似于客户端/服务器。
服务器端首先创建套件字,将其绑定到已知的本地端口,并使用WSPListen()函数设置套接字处于监听状态,等待客户端的请求,并指定连接的队列。
服务器端套接字会使用WSPAccept()函数接收客户端套接字连接,并将其放置到客户端队列中,同时创建新的对应的套接字,与客户端套接字进行数据传输和交互。
2)多线程程序设计中为什么要使用线程同步策略?
常见的线程同步对象有哪些,其具体特点是什么?
(173)
因为在程序中使用多线程时,一般很少有多个线程能在其生命期内进行完全独立的操作。
更多的情况是一些线程进行某些处理操作,而其他的线程必须对其处理结果进行了解。
正常情况下对这种处理结果的了解应当在其处理任务完成后进行。
如果不采取适当的措施,其他线程往往会在线程处理任务结束前就去访问处理结果,这就很有可能得到有关处理结果的错误了解。
例如,多个线程同时访问同一个全局变量,如果都是读取操作,则不会出现问题。
如果一个线程负责改变此变量的值,而其他线程负责同时读取变量内容,则不能保证读取到的数据是经过写线程修改后的。
为了确保读线程读取到的是经过修改的变量,就必须在向变量写入数据时禁止其他线程对其的任何访问,直至赋值过程结束后再解除对其他线程的访问限制。
所以要使用线程同步策略。
线程的同步可分用户模式的线程同步和内核对象的线程同步两大类。
用户模式中线程的同步方法主要有原子访问和临界区等方法。
其特点是同步速度特别快,适合于对线程运行速度有严格要求的场合。
内核对象的线程同步则主要由事件、等待定时器、信号量以及信号灯等内核对象构成。
由于这种同步机制使用了内核对象,使用时必须将线程从用户模式切换到内核模式,而这种转换一般要耗费近千个CPU周期,因此同步速度较慢,但在适用性上却要远优于用户模式的线程同步方式。
3)并行编程有多进程和多线程的方法,请结合课本例程grepMP和grepMT,给出多进程应用和多线程应用的特点。
(126、152)
答:
(1)多进程应用特点:
grepMP并行搜索文件,是一个被父进程所控制的可执行程序。
每个文件一个进程,Widows调度程序在不同处理器上并发运行进程,表示多进程可以并行操作的特点。
其逻辑控制复杂,需要和主程序交互。
该程序执行以下处理:
通过创建一个greppatternFK的形式命令行,对每个输入文件F1到FN,使用运行相同可执行文件的不同进程来搜索。
表明多进程中的进程及其主线程互相独立,不影响主程序的稳定性的特点。
程序通过使用WaitForMultipleObject,等候所有进程的完成,一旦搜索完成,就按顺序显示结果,一次一个,表示多进程应用可以便于顺序处理文件。
通过顺序grep和并行grepMP执行相同任务的对比,grepMP执行要快出四倍多,多进程是立体交互系统,所以尽管多进程的开销大,但执行所耗时间少性能好。
在grepMP多进程的应用中,grepMP程序的WaitForMultipleObject最多有64个句柄,所以程序会多次调用它,所有的进程都执行相同的程序。
grepMP实现了程序的并发执行和资源共享,提高了系统的效率和系统的资源利用率。
(2)多线程应用特点:
grepMT使用多线程在单一的进程中执行搜索,减少了整体系统的开销。
多线程可以实现并行处理,避免了某项任务长时间占用CPU时间。
grepMT展示了不通过使用异步I/O的显示方法,多线程的应用也能实现某种形式的异步I/O。
程序管理多个文件的并发I/O,而主线程或者任何其他线程可在等待I/O完成之前执行更多处理工作。
所以多线程应用是获取异步I/O的简单方法。
grepMT和grepMP有一个不同点,在grepMT中WaitForMultipleObject是等待单一的线程终止,而不是等待所有线程,在等待其他线程完成之前,正确的输出就已经显示出来了。
所以在大部分情况下,完成的顺序每次都不一样。
grepMT中由于MAXIMUM_WAIT_OBJECTS的值限制了WaitForMultipleObject调用可用的句柄数量,所以有64个线程的限制。
如果需要更多线程,需要创建适当的逻辑对WaitForMultipleObject循环。
grepMT中内核在线程之间切换要比在进程中切换更高效。
4)请编程举例说明WindowsNT6.X中的线程池的特点和使用方法。
答:
线程池的使用方法及特点,使用例子如下:
创建线程池工作对象,创建结果是一个工作对象句柄,用于其他函数。
每一个工作对象是一个回调函数和一个参数值。
这个句柄不是Handle而是PTP_WORK对象:
PTP_WORKCreateThreadpoolWork(PTP_WORK_CALLBACKpfnWorkHandler,PVOIDpvContext,PTP_CALLBACK_ENVIRONpche);pfnWorkHandler是一个函数指针,当线程池中的线程最终对工作项进行处理时会调用该函数。
pvContext是传给pfnWorkHandler的参数。
消息处理函数使用线程池工作对象,调用SubmitThreadpoolWork向线程池提交一个请求:
voidCThreadpoolexap1Dlg:
:
OnBnClickedBtnStart()
{
m_WorkItem=CreateThreadpoolWork(ThreadFunc,this,NULL);
if(m_WorkItem==NULL)
{
MessageBox(TEXT("工作项创建失败"));
return;
}
SubmitThreadpoolWork(m_WorkItem);
SubmitThreadpoolWork(m_WorkItem);
SubmitThreadpoolWork(m_WorkItem);
SubmitThreadpoolWork(m_WorkItem);
}
线程入口函数:
VOIDNTAPICThreadpoolexap1Dlg:
:
ThreadFunc(PTP_CALLBACK_INSTANCEInstance,PVOIDContext,PTP_WORKWork)
{
CThreadpoolexap1Dlg*pdlg=(CThreadpoolexap1Dlg*)Context;
InterlockedIncrement(&pdlg->m_CurrentTask);
DWORDnum=pdlg->m_CurrentTask;
CStrings;
s.Format(TEXT("任务%d开始运行!
"),
GetCurrentThreadId(),pdlg->m_CurrentTask);
pdlg->m_list.InsertString(-1,s);
pdlg->PostMessage(TASK_COMPELETED,0,(LPARAM)num);
}
定义了线程池线程入口函数,就需要提交请求让线程池执行该函数:
BOOLTrySubmitThreadpoolCallback(PTP_SIMPLE_CALLBACKpfnCallback,PVOIDpvContext,PTP_CALLBACK_ENVIRONpche);该函数将一个工作项添加到线程池队列中。
若调用成功,则返回true。
否则返回false。
pfnCallback表示线程池线程入口函数。
pvContext是传给线程入口函数的参数。
pche可以先传给它NULL。
当我们提交一个请求后,线程池就会创建一个默认的线程池并让线程池的一个线程来调用回调函数。
当线程从入口函数返回时,并不会销毁而是返回到线程池。
线程池会不断重复使用各个线程,而不会频繁销毁和新建线程。
取消已经提交的工作项或是等待工作项处理完毕。
可以调用WaitForThreadpoolWorkCallbacks函数,此函数将线程挂起,直到工作项处理完毕:
当不需要一个工作项时,可以调用CloseThreadpoolWork。
VOIDCloseThreadpoolWork(PTP_WORKpwk);
5)请给出设计一个Windows服务例程的过程。
(293)
答:
Windows服务,提供将服务器转换为可以用命令或者在启动时初始化的服务所需的管理能力,初始化可以发生在任何用户登录之前,服务可以暂停、恢复、终止、监控。
通过注册表维护与服务有关的信息。
Windows提供许多服务,比如DNS客户、许多SQLServer服务以及终端服务,这些服务在服务控制管理器(SCM)的控制下运行。
设计服务例程的过程:
创建Windows服务项目;
利用CreateService()函数注册一个服务;
重新编写其他所有的其定义的功能(如启动,停止,继续等);
添加服务应用程序所需的安装程序;
生成项目,安装服务。
题目二
Windows操作系统中对I/O操作进行了非常好的设计,把文件和所有其他的输入输出设备的操作都统一由CreateFile等系列函数完成,论述I/O操作的同步方式和异步方式各自的特点。
异步方式主要由4种实现形式,从理论描述和实践编写程序2个方面分别论述这4种形式的异同,并掌握它们的运用方法,必须要给出程序的设计思考过程和关键程序代码。
1.同步异步方式各自的特点
答:
(1)I/O同步方式特点:
同步I/O方式中的I/O请求必须等到操作确认完成,所以性能受到限制,在同步I/O中,操作的发起者必须等到硬件处理完I/O,才返回操作的结果。
同步I/O模型中,对API的调用只在请求操作完成时才返回。
同步I/O易理解,使用较简单。
I/O异步方式特点:
异步I/O操作在后台运行,I/O操作和应用程序可以同时运行,从而提高了系统的性能。
异步I/O的I/O请求独立于I/O处理流程,在I/O处理过程中允许其他例程继续执行,当I/O完成以后,内核才通知应用程序。
异步I/O操作还可以减少memorycopy带来的性能损耗。
2异步方式四种实现方式
1)触发设备内核对象
线程发出一个异步IO请求后,将继续执行。
但即使如此,线程还需要在一点上等待设备内核对象被触发。
ReadFile和WriteFile函数在将IO请求添加到队列之前,会将设备内核对象设为非触发状态。
当设备驱动程序完成了请求,驱动程序将设备内核对象设为触发状态。
线程可以通过调用WaitForSingleObject或WaitForMultipleOBjecs来检查一个异步IO请求是否已经完成。
HANDLE hFile=CreateFile(...,FILE_FLAG_OVERLAPPED,...);
BYTE buff[1000];
OVERLAPPED o={0};
o.Offset=345;
BOOL bReadDone=ReadFile(hFile,bBuff,100,NULL,&o);//异步则返回false.
DWORD ret=GetLastError();//异步则返回ERROR_IO_PENDIN。
if(!
bReadDone&&(ret==ERROR_IO_PENDING))//以异步IO执行。
{
WaitForSingleObject(hFile,INFINITE);
}
上述代码中首先发出了一个异步设备IO请求,然后立即等待请求完成。
这就与同步设备IO请求无异,枉费了异步设备IO的设计意图。
实际上并不怎么有用。
如果向一个设备同时发出多个IO请求,这种方法是不行的。
2)触发事件内核对象
发送异步I/O请求,传入的OVERLAPPED结构最后一个成员hEvent用来标识一个事件内核对象,我们必须通过CreateEvent来创建你该对象。
当一个异步I/O请求完成的时候,设备驱动程序会检查hEvent成员是否为NULL,不为NULL则触发该事件,所以我们可以等待每个异步I/O请求的hEvent事件是否触发来判断是否完成请求。
多个异步设备I/O请求必须为每个请求创建不同的事件对象。
我们可以使用GetOverlappedResult来获得异步I/O的结果:
BOOL
GetOverlappedResult(
HANDLE hFile, // 设备句柄;
LPOVERLAPPED lpOverlapped, // 异步I/O请求时传入的OVERLAPPED结构体;
LPDWORD lpNumberOfBytesTransferred, // 传输的字节;
BOOL bWait // 是否等待请求完成;
我们也可以自己等待hEvent成员触发,然后自己检查OVERLAPPED的Internal来判断错误码,InternalHigh判断传输的字节。
为了略微提高性能,我们可以使用函数SetFileCompletionNotificationModes设置不触发第一种情况下所说的设备内核对象:
BOOL
SetFileCompletionNotificationModes(
HANDLE FileHandle, // 设备句柄;
UCHAR Flags // 标志,传入FILE_SKIP_SET_EVENT_ON_HANDLE;
);
3)可提醒I/O
首先需要知道的是,可提醒I/O设计的非常糟糕,所以应该避免使用!
每个线程创建的时候都会创建一个异步过程调用队列,当发出一个I/O请求的时候,我们可以告诉设备驱动程序在调用线程的APC队列中添加一项。
为了能够实现我们的调用ReadFileEx和WriteFileEx函数来完成异步I/O请求,该两个函数和原先函数相比,少了返回已经传输的字节数,多了最后一个LPOVERLAPPED_COMPLETION_ROUTINE参数,该参数是一个回调函数,函数形式如下:
VOID
(WINAPI *LPOVERLAPPED_COMPLETION_ROUTINE)(
DWORD dwErrorCode, // 错误码;
DWORD dwNumberOfBytesTransfered, // 实际传输的字节;
LPOVERLAPPED lpOverlapped // 异步请求时候的OVERLAPPED结构体;
);
使用ReadFileEx和WriteFIleEx发出的请求会将回调函数地址传给设备驱动程序,当请求完成的时候,会向发出请求的线程的APC队列中添加一项。
顺便提下,可提醒I/O完成时不会触发OVERLAPPED的hEvent成员,所以可以占为己用。
当线程处于可提醒状态,系统会检查它的APC队列,对队列中的每一项,都会调用完成函数并传入参数。
当I/O请求完成时候,系统将他们会添加到APC队列中——并不会立即调用。
线程为了对APC队列的项进行处理,必须将自己置为可提醒状态。
Windows提供了6个函数可将线程置为可提醒状态:
SleepEx,WaitForSingleObjectEx,WaitForMultipleObjectsEx,SingalObjectAndWait,GetQueuedCompletionStatusEx,MsgWaitForMultipleObjectsEx。
前5个参数最后一个参数是个BOOL值,表示是否将线程置为可提醒状态,最后一个函数的最后一个参数必须使用标志MWMO_ALERTABLE来让线程进入可提醒状态。
当使用这些函数调用等待函数并设置可提醒状态时,如果APC队列有项,则他们并不会被挂起。
可提醒I/O的劣势:
1.可提醒必须创建一个回调函数,是代码变得复杂,因为我们不得不把换掉函数用到的信息放在全局变量中。
2.线程问题,发出I/O请求的线程必须同时对完成通知进行处理,伸缩性不是很好。
可提醒I/O的优点:
Windows提供函数QueueUserAPC手动向将一项添加到APC队列中:
DWORD
QueueUserAPC(
PAPCFUNC pfnAPC, // 回调函数;
HANDLE hThread, // 线程句柄;
ULONG_PTR dwData // 传入回调函数的参数;
);
回调函数指针原型:
VOID
(NTAPI *PAPCFUNC)(
ULONG_PTR Parameter // QueueUserAPC的第3个参数;
);
hThread标识的线程可以在另一个进程的地址空间中,如果是那样那么pfnAPC也必须在同一个进程的地址空间中。
QueueUserAPC可以用来强制让线程退出等待状态:
如果某一个线程正在等待,并且该线程是可提醒的,我们可以向它APC队列添加项来使它根据等待函数返回的内容来判断是否退出,处理APC队列的等待函数返回的是WAIT_IO_COMPLETION。
4)I/O完成端口
完成端口是到目前为止伸缩性最好的处理I/O请求的方法,他可以让用户创建等待请求线程,然后在另外一个线程完成请求,适合多个并发操作的请求,例如套接字请求。
这里指介绍完成端口的使用方法:
HANDLE // 返回创建的句柄;
CreateIoCompletionPort(
HANDLE FileHandle, // 设备句柄;
HANDLE ExistingCompletionPort, // 当前存在的完成端口句柄,用于与设备句柄关联;
ULONG_PTR CompletionKey, // 关键字,通常是一个结构体指针,标识I/O的请求,该指针会在结果中返回;
DWORD NumberOfConcurrentThreads // 允许并发线程数目,通常为0表示等于CPU数目;
);
使用该函数最常用的是,先创建一个完成端口,然后与设备进行关联:
// 创建完成端口;
HANDLE hComplete = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, 0 );
// 与设备句柄关联;
CreateIoCompletionPort( hFile, hComplete, dwKey, 0 );
也可以在创建的时候直接关联:
// 创建完成端口的时候直接关联;
HANDLE hComplete = CreateIoCompletionPort( hFile, NULL, dwKey, 0 );
如果我们的设备已经与完成端口关联,但是我们发出一个的请求,使它在完成时候不添加到I/O完成端口队列中,则我们需要设置发送请求的OVERLAPPED的hEvent成员:
// 创建OVERLAPPED对象,并让hEvent与按位1或起来;
OVERLAPPED ol = {0};
ol.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
ol.hEvent = (HANDLE)((DWORD_PTR)ol.hEvent | 1 );
ReadFile(..., &ol);
// 关闭事件的时候不要忘了将低位清除;
CloseHandle( (HANDLE)((DWORD_PTR)ol.hEvent & ~1) );
另外提一个,如果关联了完成端口的设备,在发送同步请求的时候,请求完成Windows也会将结果放到完成队列中,为了略微提高性能,可能使用上面提到的SetFileCompletionNotificationModes函数,第一个参数传入设备句柄,第二个参数传入FILE_SKIP_COMPLETION_PORT_ON_SUCCESS告诉Windows不要将以同步方式完成的请求放到完成端口中。
以上就是I/O异步操作的4中形式。
题目三
教材P92至P95页的程序sortBT(使用二叉排序树进行排序)的主功能(5分),并逐行添加注释(25分)。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 高级 程序设计 期末 作业 重庆 科技学院