您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 管理学资料 > 11程序设计实践6w-线程、模块化、时间函数和设计问题
模块化设计问题1提纲1.使用线程实现任务并发2.模块化和工程3.概要设计要点4.时间控制函数5.有限状态自动机解题21.使用线程实现任务并发•问题的引出:以电梯控制系统为例•目前能想到的程序主体结构main(){while(1){state_trans();//计算此刻电梯的状态print_message();//输出电梯此刻的状态,包括动画get_input();//接收当前时刻的新输入(包括新目标和新呼叫)control();/*根据控制策略确定下一目标楼层,在state_trans()中要用到*/time_count();//时间片推进一个}}•思考:上述结构不合理之处?31.使用线程实现任务并发•上述结构不合理之处:计算和输出电梯状态与接收服务请求是串行的,与现实中的电梯运行不符!•程序结构的改进:从上述代码中删除get_input(),从而实现每隔一小段时间就刷新电梯当前状态main(){while(1){state_trans();//计算此刻电梯的状态print_message();//输出电梯此刻的状态control();/*根据控制策略确定下一目标楼层,这在state_trans()中要用到*/time_count();//时间片推进一个}}41.使用线程实现任务并发•但是,程序必须要能接收电梯服务请求,如何处理服务请求的输入?•理想状态:–电梯服务请求的接收和电梯状态的计算输出能同时进行,互不影响–但是,能否实现?–答案是:使用线程电梯状态计算和输出共享内存区接收服务请求51.使用线程实现任务并发进程–一个正在运行的程序的实例,是一个程序在其自身的地址空间中的一次执行活动,例如用字处理软件编辑文稿时,同时打开mp3播放程序听音乐,这两个独立的程序在同时运行,称为两个进程–进程是资源申请、调度和独立运行的单位61.使用线程实现任务并发•线程–线程是系统分配处理器时间资源的基本单元。对于操作系统而言,其调度单元是线程(为线程提供时间片,线程在自己的时间片内运行)。–一个程序中多段代码同时并发执行,称为多线程譬如用word同时打开多个文档进行编辑,用IE浏览器同时访问多个网站–通过多线程,一个进程表面上看同时可以执行一个以上的任务——并发7线程(续)–一个进程至少包括一个线程(称为主线程)。一个进程从主线程的执行开始进而创建一个或多个附加线程,就是所谓基于多线程的多任务。–线程自己不拥有系统资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源81.使用线程实现任务并发在C程序中要创建线程,可以调用Windows操作系统提供的创建线程的函数CreateThread:HANDLECreateThread(LPSECURITY_ATTRIBUTESlpThreadAttributes,DWORDdwStackSize,LPTHREAD_START_ROUTINElpStartAddress,LPVOIDlpParameter,DWORDdwCreationFlags,LPDWORDlpThreadId);LPVOID是一个Void类型的指针,也就是说你可以将任意类型的指针赋值给LPVOID类型的变量。DWORD是32位无符号整数。91.使用线程实现任务并发•lpThreadAttributes表示创建线程的安全属性,NT下有用。可赋值为NULL。•dwStackSize指定线程栈的尺寸,如果为0则与进程主线程栈相同。•lpStartAddress指定线程开始运行的地址。赋值为指向函数的指针,即函数名。该函数的名称任意,但函数类型必须遵照下述声明形式:DWORDWINAPIThreadProc(LPVOIDlpParameter);否则需要进行强制类型转换•lpParameter表示传递给线程的32位的参数(数值或指针)。若无参数则赋值为NULL。•dwCreationFlags表示是否创建后挂起线程(取值CREATE_SUSPENDED表示挂起,取值0表示创建后立即运行),挂起后调用ResumeThread继续执行。若不挂起则赋值为0。•lpThreadId用来存放返回的线程ID。DWORDThreadID1=1;HANDLEhRead1=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)getInput,NULL,0,&ThreadID1);10#includestdio.h#includewindows.hDWORDWINAPIFun1Proc(LPVOIDlpParameter);intmain(){HANDLEhThreadl;//1hThreadl=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);//2CloseHandle(hThreadl);//3printf(mainthreadisrunning\n);//4return0;}11DWORDWINAPIFun1Proc(LPVOIDlpParameter){printf(hThreadlisrunning\n);return0;}例112#includestdio.h#includewindows.hDWORDWINAPIFun1Proc(LPVOIDlpParameter)intmain(){HANDLEhThreadl;//1hThreadl=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);//2CloseHandle(hThreadl);//3printf(mainthreadisrunning\n);//4Sleep(10);//让线程睡眠10毫秒return0;}例2#includestdio.h#includewindows.hintindex=0;DWORDWINAPIFun1Proc(LPVOIDlpParameter);intmain(){HANDLEhThreadl;//1hThreadl=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);//2CloseHandle(hThreadl);//3while(index++1000){printf(mainthreadisrunning\n);//4}return0;}13例3DWORDWINAPIFun1Proc(LPVOIDlpParameter){while(index++1000){printf(hThreadlisrunning\n);}return0;}1415#includestdio.h#includewindows.hinttickets=100;DWORDWINAPIFun1Proc(LPVOIDpPararneter){while(tickets0)printf(“thread1sellticket:%d\n”,tickets--);return0;}DWORDWINAPIFun2Proc(LPVOIDpPararneter){while(tickets0)printf(“thread2sellticket:%d\n”,tickets--);return0;}intmain(){HANDLEhThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);HANDLEhThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);CloseHandle(hThread1);CloseHandle(hThread2);Sleep(4000);return0;}1617•线程的同步–利用互斥对象(mutex)实现线程的同步,互斥对象能够确保线程拥有对单个资源的互斥访问权。–3个操作互斥对象的创建互斥对象的释放互斥对象的请求18互斥对象的创建–HANDLECreateMutex(LPSECURITY_ATTRIBUTESlpMutexAttributes,BOOLbinitialOwner,LPCTSTRlpNarne)lpMutexAttributes:可以给该参数传递NULL值,让互斥对象使用默认的安全性binitialOwner:BOOL类型,指定互斥对象初始的拥有者。如果该值为真,则创建这个互斥对象的线程获得该对象的所有权;否则,该线程将不获得所创建的互斥对象的所有权。lpName:指定互斥对象的名称。如果此参数为NULL.则创建一个匿名的互斥对象。如果调用成功,该函数将返回所创建的互斥对象的句柄19互斥对象的释放•BOOLReleaseMutex(HANDLEhMutex);ReleaseMutex函数只有一个HANDLE类型的参数,即需要释放的互斥对象的句柄。该函数的返回值是BOOL类型,如果函数调用成功,返回非0值;否则返回0值。20互斥对象的请求•DWORDWaitForSingleObject(HANDLEhHandle,DWORDdwMilliseconds);–Handle:所请求的互斥对象的句柄。一旦互斥对象处于有信号状态,则该函数就返回。如果该互斥对象始终处于无信号状态,即未通知的状态,则该函数就会一直等待,这样就会暂停线程的执行。–dwMilliseconds:指定等待的时间间隔,以毫秒为单位。如果指定的时间间隔己过,即使所请求的对象仍处于无信号状态,WaitForSingleObject函数也会返回。如果将此参数设置为0,那么WaitForSingleObject函数将测试该对象的状态并立即返回;如果将此参数设置为INFINITE,则该函数会永远等待,直到等待的对象处于有信号状态才会返回。•调用WaitForSingleObject函数后,该函数会一直等待,只有在以下两种情况下才会返回:1)指定的对象变成有信号状态。2)指定的等待时间间隔己过。21HANDLEhMutex;inttickets=100;DWORDWINAPIFun1Proc(LPVOIDpPararneter){while(tickets0){WaitForSingleObject(hMutex,INFINITE);if(tickets0)printf(thread1sellticket:%d\n,tickets--);ReleaseMutex(hMutex);}return0;}22DWORDWINAPIFun2Proc(LPVOIDpPararneter){while(tickets0){WaitForSingleObject(hMutex,INFINITE);if(tickets0)printf(thread2sellticket:%d\n,tickets--);ReleaseMutex(hMutex);}return0;}23intmain(){HANDLEhThread1,hThread2;hMutex=CreateMutex(NULL,FALSE,NULL);hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);CloseHandle(hThread1);CloseHandle(hThread2);Sleep(4000);return0;}24线程在电梯控制系统中的使用•考虑现实中安装在电梯上的软件:接收电梯服务请求和计算电梯状态、从而控制电梯的运行是并行的•因此我们可以考虑在模拟电梯控制系统中设计一个线程专门用于接收电梯服务请求,另一个线程实行电梯的状态计算和状态输出电梯状态计算和输出线程共享内存区接收服务请求电梯状态计算和输出:从共享内存区读取电梯请求,计算下一目标楼层,从而确定电梯的下一状态。接收服务请求:接收电梯请求,将请求保存到内存。25//主线程main
本文标题:11程序设计实践6w-线程、模块化、时间函数和设计问题
链接地址:https://www.777doc.com/doc-721394 .html