


版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、创建线程,利用互斥实现线程共享变量通信概述1.1课题目的和意义掌握线程创建和终止,加深对线程和进程概念的理解,会用同步与互斥方法实现线程之间 的通信。1.2内容和要求软件界面上点“创建线程”按钮,创建三个生产者线程(P1, P2, P3)和两个消费者线程(C1, C2),生产者和消费者线程共享一个长度为 2KB的环型公共缓冲区,生产者向其中投放消 息,消费者从中取走消息。只要缓冲区未满,生产者可将消息送入缓冲区;只要缓冲区未空, 消费者可从缓冲区取走一个消息。每个消息具下列结构格式:消息头(1B,固定为Oxaa),消息长度(1B),消息内容(nB),校验和(1B),检验和计算 方式为消息长度和
2、消息内容所有字节异或结果。每个生产者每隔n毫秒(n用随机数产生,1到100毫秒之间,间隔不固定)生产一个消息 加入缓冲区,并把消息产生时间和内容记录在一个文本文件中(或显示在列表框中)。P1每次生产的数据为26个大写字母,P2每次生产的数据为26个小写字母,P3每次生产的数据为10个 数字。每个消费者每隔n秒(n用随机数产生,1到5秒之间,间隔不固定)从缓冲区取走一个消 息。每消费一个消息需要将消费时间和消息内容记录在一个文本文件中(或显示在列表框中)。当用户按结束按钮时结束5个线程,并将5个文件内容显示出来进行对照。这期实是一个经典的生产者一消费者(Producer_consumer)进程(
3、线程)同步的问题。它描 述的是:有一群生产者进程在生产产品,并将此产品提供给消费者进程(线程)去消费。为使生产者进程和消费者进程(线程)能并发执行,在它们之间设置有个缓冲区的缓冲池,生产者进程(线程)可将它所生产的产品放入一个缓冲区中,消费者进程(线程)可从一个缓冲区取得一个产品消费。尽管所有的生产者进程和消费者进程(线程)都是以异步的方式运行的,但它们之间必须保持 同步,即不允许消费者进程(线程)到一个空缓冲区去取产品,也不允许生产者进程 (线程)向一个 已装有消息尚未被取走产品的缓冲区投放产品。如下图所示:."消彷希1消费者2訂个大小相尊的缓冲区,毎 个缓冲赳用冷放一个消息1.3
4、线程所采用的同步方法同步是多线程中的重要概念同步的使用可以保证在多线程运行的环境中,程充不会产生设 计之外的结果同步的实现方式有两种,同步方法和同步块线程在执行同步方法是具有排它性的.当任意一个线和进入到一个对象的任意一个同步方 法时,这个对象所有同步方法都被锁定,在些期间,期他任何线程都不能访问这个对象的任意一 个同步方法,直到这个线程执行完它所调用的同步方法并从中退出,从而导至它释放了该对象的同步锁这后.在一个对象被某个线程锁定之后,其他线程是可以访问.同步的有几种实现方法,分别是:wait():使一个线程处于等待状态,并且释放所有持有的对象lock.sleep():使一个正在运行的线程处
5、于睡眠状态,是一个静态方法,调用此方法要捕捉In terruptedExceptio n异常。n otify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤 醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。All notity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。1.4开发工具平台开发平台:window XP 开发工具:VC+数据定义和详细说明1数据定义设计PV操作算法,用信号量机制实现生产者与消费者同步与互斥问题,并与无 PV情况下 进行对比。定义20个缓冲区,将其初始化为0。调用随机函数r
6、and ()生成随机数,把随机数 通过生产者放入缓冲区。若缓冲区满则其值非0。当消费者从缓冲区中去数后缓冲区值变为0。程序可显示缓冲区中的全部内容,方便观察生产者与消费者的行为。程序可通过设置sleep(time) 中time的值来控制生产者与消费者的执行顺序。2详细说明为了实现生产者与消费者同步与互斥的问题,该程序用记录型信号量机制来实现。假定在生产者与消费者之间,利用一个公共的缓冲池来进行通信,生产者将所生产的信息 放入其中,消费者cognitive缓冲池中取得消息来消费,该缓冲池具有n个缓冲区,其编号为0, 1, 2, 3,n-1 ;设置一个互斥信号量 mutex,用于实现诸进程对缓冲池
7、的互斥使用,其初值 为1,利用资源信号量empty,表示缓冲池中空缓冲区的数目,其初值为n; full分别表示缓冲池中满缓冲区的数目,其初值为0.又假定这些生产者和消费者相互等效,只要缓冲池未满,生产者便可将消息送入由指针in所指的缓冲区;只要缓冲池未空,消费者变可以从由指针out所指示的缓冲区中,取走一个消息。对生产者消费者的问题可以描述如下:Var metux,empty,full:semaphore=1, n,0;Buffer:arrayO, n-1 of item;ln,o ut:i nteger:=0;Begi n:Pabegi nProducer:begi nRepeatProdu
8、cer an item n extp;P(empty);P(mutex);buffer(i n):=nextp; in :=(i n+1)mod n;V(mutex);V(full);Un til false;EndCon sumer:beg inRepeatP(full);P(mutex); n extc:= buffer(out); out:=(out+1)mod n; V(mutex);V(empty); Un til false;EndPare ndEnd实现思想和设计流程1实现思想我们把系统中使用某一类资源的进程(线程)称为该资源的消费者,而把释放同类资源的进 程称为该资源的生产者。
9、例如在计算进程 (线程)与打印进程(线程)公用一个缓冲区时,计算进 程(线程)把数据送入缓冲区,打印进程(线程)从缓冲区中取数据打印输出,因此,计算进程相 当于数据资源的生产者,而打印进程相当于消费者,二者之间必须保持同步。基于这一问题, 我们将使用生产者和消费者这一同步机制算法来处理该问题 2设计流程首先,我们知道,生产者一消费者问题是一个同步问题。即生产者和消费者之间应满足如 下条件:2.1消费者想接收数据时,有界缓冲区中至少有一个单元是满的。2.2生产者想发送数据时,有界缓冲区中至少有一个单元是空的。另外,由于有界缓冲区是临界资源,因此,各生产者进程和各消费者进程之间必须互斥。 其次,我
10、们还必须考虑 面临的问题是属于进程互斥还是进程同步,或是互斥与同步的混合问题。 然后根据共享资源的数量以及使用共享资源的规则正确的定义信号量及其初值。最后,还要对结果进行分析处理。若结果中生产和消费进程都已处理完时,但还可能出现 以下两种情况:一是还有生产进程,但没有空缓冲,且消费进程暂时已完,所以此时,只能结 束等待新的消费进程产生空缓冲。二是还有消费进程,但没有了满缓冲,且生产进程暂时已完, 此时,只能结束等待新的生产进程来输入数据,产生新的满缓冲等。在程序中应能作出相应的 判断和处理。本程序的执行是在C+勺环境中通过手动输入生产者和消费者线程的运行速度来控制程序 的运行的。为了实现生产者
11、进程能把生产出来的产品正确的存入缓冲区,和消费者进程能够从 缓冲区中取产品进行消费,防止因等待资源而出现死锁的现象,首先设置两个时间:生产者生 产一个产品后等待的时间t1,和消费者消费一个产品后等待的时间t2,来控制生产者和消费者 进程执行的速度。其函数原形是sleep(tl)和sleep(t2)其中t1、t2指定义挂起执行线程的时间,以毫秒为 单位,取值为0时,该线程将余下的时间片交给处于就绪状态的同一优先级的其他线程。若没 有处于就绪状态的同一优先级的其他线程,则函数立即返回。3程序流程图创建进程模拟生产者消费者Y4关键代码分析本程序采用了 MFC可视化界面来完成,现在给出关键代码来分析
12、4.1开始创建线程原代码:void CMultiThreadDIg: On Start() /开始创建线程hMutex=CreateMutex(NULL,FALSE,NULL); 创建互斥对象threadC on troller=1;check=TRUE;检测标识HWND hWnd=GetSafeHw nd();/得到控制权AfxBegi nThread(ThreadProc,hWnd,THREAD_PRIORITY_NORMAL)启用生产者线程 1(P1)AfxBeginThread(ThreadProc2,hWnd,THREAD_PRIORITY_NORMAL)启用生产者线程 2(P2)A
13、fxBeginThread(ThreadProc3,hWnd,THREAD_PRIORITY_NORMAL)启用生产者线程 3(P3)AfxBeginThread(Thread_consumer,hWnd,THREAD_PRIORITY_NORMAL)启用 消费者线程 1(S1)AfxBeginThread(Thread_consumer2,hWnd,THREAD_PRIORITY_NORMAL)启 用消费 者线程 2(S2)原码功能:主要创建生产者和消费者线程,创建互斥对象,创建窗体对象主要函数功能:4.1.2 CreateMutex()函数功能:该函数是创建有名或者无名的互斥对象。函数原型
14、:HANDLE CreateMutex(LPSECURITY_ATTRIBUTES IpMutexAttributesBOOL blnitialOwner, LPCTSTR lpName);参数:lpMutexAttributes :指向SECURITY_ATTRIBUT结S勾的指针,该结构决定子进程是 否能继承返回句柄。如果lpMutexAttributes 为NULL那么句柄不能被继承。在Windows NT中该结构的IpSecurityDescriptor成员指定新互斥对象的安全描述符。如果lpMutexAttributes 为NULL那么互斥对象获得缺省的安全描述符。bI nitial
15、Ow ner :指定互斥对象的初始所属身份。如果该值为TRUE并且调用者创建互斥对象,那么调用线程获得互斥对象所属身份。否则,调用线程不能获得互斥对象所属身份。判断 调用者是否创建互斥对象请参阅返回值部分。lpName:指向以NULL结尾的字符串,该字符串指定了互斥对象名。该名字的长度小于MAX_PAT且可以包含除反斜线路径分隔符( )以外的任何字符。名字是区分大小写的。如果与已存在的有名互斥对象名相匹配,那么该函数要求用权限访问已存在的对象。在这种情况下,由于参数己被创建进程所设置,该参数被忽略。如果参数不为,它决定句柄是否解除继承,但是其安全描述符成员被忽略。如果lpName为NULL那么
16、创建的互斥对象无名。如果lpName与已存在的事件、信号量、可等待定时器、作业、或者文件映射对象的名字相匹配,那么函数调用失败,并且GetLastError函数返回ERPORNVALID_HANDL其原因是这些 对象共享相同的名字空间。返回值:如果函数调用成功,返回值是互斥对象句柄;如果函数调用之前,有名互斥对象 已存在,那么函数给已存在的对象返回一个句柄,并且函数GetLastError返回ERROR_ALREADY_EX,否则,调用者创建互斥对象。如果函数调用失败,则返回值为NULL若想获得更多错误信息,请调用GetLastError函数。 如果CreateMutex中的IpMutexAt
17、tributes参数允许继承,由 CreateProcess函数创建的子进程可以继承父进程的互斥对象句柄。一个进程可以在调用DuplicateHa ndle函数时指定互斥对象句柄来创建一个可以被其他进 程使用的双重句柄。一个进程在调用OpenMutex或CreateMutex函数时能指定互斥对象名。使用CloseHandle函数关闭句柄,进程结束时系统自动关闭句柄。当最后一 个句柄被关闭时,互斥对象被销毁。4.1.3 GetSafeHw nd()功能:到一个窗口对象(CWn啲派生对象)指针的句柄(HWND函数原型:HWND hwnd = pwnd->GetSafeHwnd();函数用法:
18、CWnd *pwnd = FindWindow( “ExploreWClass” ,NULL); / 希望找到资源管理器HWND hwnd = pwn d->m_hw nd; /得到它的 HWND这样的代码当开始得到的pwnd为空的时候就会出现一个"Ge neral protection error ” ,并关闭应用程序,因为一般不能对一个NULL指针访问其成员,如果用下面的代码:CWnd *pwnd = FindWindow( “ExploreWClass” ,NULL); / 希望找到资源管理器HWND hwnd = pwn d->GetSafeHw nd(); /得
19、到它的 HWND就不会出现问题,因为尽管当pwnd是NULL时,GetSafeHwnd仍然可以用,只是返回NULL,通过 GetSafeHw nd()的实现代码就更清楚了:_AFXWINN LINE HWND CWnd:GetSafeHw nd() constreturn this = NULL?NULL:m_hWnd;4.1.4 AfxBegi nThread()功能:用于创建工作者线程函数原型:CWin Thread* AfxBegi nThread( AFX_THREADPROC pfnThreadProc,LPVOID pParam,i nt nPriority = THREAD_PR
20、IORITY_NORMAL,UINT n StackSize = 0,DWORD dwCreateFlags = 0, LPSECURITY _ATTRIBUTES lpSecurityAttrs= NULL);返回值:一个指向新线程的线程对象.pfnThreadProc : 线程的入口函数,声明一定要如下:UINT MyThreadFunction( LPVOID pPara m );pParam :传递入线程的参数,注意它的类型为:LPVOID,所以我们可以传递一个结构体入线程. nPriority :线程的优先级,一般设置为0 .让它和主线程具有共同的优先级.nStackSize :指定
21、新创建的线程的栈的大小.如果为0,新创建的线程具有和主线程一样的大 小的栈 dwCreateFlags :指定创建线程以后,线程有怎么样的标志.可以指定两个值:CREATE_SUSPENDE线程创建以后,会处于挂起状态,直到调用:ResumeThreadO:创建线程后 就开始运行IpSecurityAttrs:指向一个SECURITY_ATTRIBUTE的结构体,用它来标志新创建线程的安全性如果为NULL,那么新创建的线程就具有和主线程一样的安全性.如果要在线程内结束线程,可以在线程内调用AfxEndThread.4.2生产者线程原码:UINT CMultiThreadDlg:ThreadPr
22、oc(LPVOID param)/ 生产者 1 的生产过程while(threadC on troller)WaitForSi ngleObject(hMutex,INFINITE);等待一个同步事件的到来if(n umber<20)srand (u nsig ned)time(NULL);/返回一个随机数int n;n=rand()%9+1;随机显示字数Sleep( n*100);CStri ng str;CStri ng str_;for(i nt i=0; i<n; i+)/循环随机的字数str_.Format("%c",65+ra nd()%9+1);显
23、示大写字母str.I nsert(i,str_);插入成一列list .AddTail(CStri ng(str);CStri ng stri ng;strin g.Format("%s%d%s%d","0xaa", n, list.GetTail(),sizeof(list.GetTail()Asizeof(n);/按格式消息头(1B,固定为0xaa),消息长度(1B),消息内容(nB),校验和(1B)pbox1->AddStri ng(stri ng);/ 打印nu mber+;ReleaseMutex(hMutex);/ 释放互斥原码功能:当
24、生产者线程1得到控制权,等待同步事件,产生随机个数(n),按产生的随机数显示n 个大写字母,利用sleep函数来隔时存储到缓冲区,最后按格式消息头(1B,固定为0xaa),消息 长度(1B),消息内容(nB),校验和(1B)的方式输出.主要函数功能:421 WaitForSi ngleObject()函数功能:当如下情况之一发生时该函数返回:指定对象处于信号态;超时。函数原型:DWORD WaitForSingleObject( HANDLE hHandle,DWORD dwMilliseconds);参数:hHandle:等待对象句柄。若想了解指定句柄的对象类型列表,参阅下面说明部分。在Wn
25、dowsN中,句柄必须有SYNCHRONIZE问权限。若想获得更多的信息,请查看Standard Access Rights。dwMilliseconds :指定以毫秒为单位的超时间隔。如果超时,即使对象的状态是非信号态 的并且没有完成,函数也返回。如果 dwMilliseconds是0,函数测试对象的状态并立刻返回: 如果dwMillseconds是INFINlTE,函数从不超时。返回值:如果函数调用成功,返回值表明引起函数返回的事件。可能值如下: WAIT_ABANDONE指定对象是互斥对象,在线程被终止前,线程没有释放互斥对象。互 斥对象的所属关系被授予调用线程,并且该互斥对象被置为非信
26、号态。WAIT_OBJECT_0指定对象的状态被置为信号态。WAIT_TIMEOUT超时,并且对象的状态为非信号态。如果函数调用失败,返回值是WAIT_FAILED若想获得更多错误信息,请调用GetLastError 函数。4.2.2 ReleaseMutex()函数功能:该函数放弃指定互斥对象的拥有权。函数原型:BOOL ReleaseMutex(HANDLE hMutex)参数:hMutex:互斥对象句柄。为 CreateMutex或OpenMutex函数的返回值。返回值:如果函数调用成功,那么返回值是非零值;如果函数调用失败,那么返回值是零 值。若想获得更多错误信息,请调用 GetLas
27、tError函数。备注:如果调用线程不拥有互斥对象,ReleaseMutex函数失败。一个线程通过调用等待函数拥有互斥对象。创建该互斥对象的线程也拥有互斥对象,而不 需要调用等待函数。当互斥对象的所有者线程不再需要互斥对象时,它可以调用ReleaseMutex函数。当一个线程拥有一个互斥对象后,它可以用该互斥对象多次调用等待函数而不会阻塞。这 防止一个线程等待一个它已拥有的互斥对象时出现死锁。不过,为了释放所有权,该线程必须 为每一个等待操作调用一次 ReleaseMutex函数。4.2.3 Sleep()函数功能:该函数对于指定的时间间隔挂起当前的执行线程。函数原型:void Sleep(D
28、WORD dwMilliseco nds);参数:dwMilliseconds :定义挂起执行线程的时间,以毫秒为单位。取值为 0时,该线程 将余下的时间片交给处于就绪状态的同一优先级的其他线程。若没有处于就绪状态的同一优先 级的其他线程,则函数立即返回,该线程继续执行。若取值为INFINITE则造成无限延迟。返回值:该函数没有返回值。备注:一个线程可以在调用该函数时将睡眠时间设为0毫秒,以将剩余的时间片交出。使用Sleep函数和直接或间接创建窗口的代码时必须非常小心。若线程创建了窗口,它就必须处理消息。消息广播被发送给系统中的所有窗口。若有一个线程调用Sleep函数时使用了无限延迟,则系统会
29、死锁。两个直接创建窗口的代码的例子是DDE和COM Colnitialize 。因此,若有一个创建窗口的线程,则使用 MsgWaitForMutipleObjects 和 MsgWaitForMutipleObjectsEx 函数,而不 使用Sleep()函数。424 GetTail()函数功能:获取此列表中的头元素函数原型:CTypedPtrList:GetTail参数:指定保存在列表中的元素类型的模板参数返回值:如果是通过一个指向const CTypedPtrList的指针访问此列表,贝U GetTail返回一个类型由模板参数TYPE指定的指针。这使此函数只能被使用在赋值语句的右边,这样就
30、保护 了列表不被修改。如果列表被直接访问,或通过一个指向CTypedPtrList的指针访问,则GetTail返回对一个类型由模板参数TYPE指定的指针的引用。这使得此函数可以使用在赋值语句的任何一边,从而允 许该列表可以被修改备注:在调用GetTail之前,你必须保证该列表不是空的。如果列表是空的,则Microsoft基础类库的调试版将给出断言。使用IsEmpty来检验列表是否包含元素。4.3消费者线程原码:UINT CMultiThreadDlg:Thread_co nsumer(LPVOID param)/ 消费者while(threadC on troller)WaitForSi ng
31、leObject(hMutex,INFINITE);等待同步事件if(nu mber>0) 缓冲区有内容sran d (un sig ned)time(NULL);int n;n=ra nd()%4+1;Sleep(n*1000); 延时 1-5 秒CStri ng stri ng;stri ng.Format("%s%d%s%d","0xaa",strle n(list.GetHead(),list.GetHead(),si zeof(list.GetTail()Fsizeof(strle n( list.GetHead();得到缓冲区内容pbo
32、x4->AddStri ng(stri ng);list.RemoveHead();删除头内容nu mber-;ReleaseMutex(hMutex);/ 释放互斥else/否则解除互斥ReleaseMutex(hMutex);return 0;原码功能:执行消费费线程,当缓冲区有数据时取出内容,并且按随机时间(1-5秒的范围内)取数, 按固定的格式消息头(1B,固定为0xaa),消息长度(1B),消息内容(nB),校验和(1B)做输出.4.3.1 Sleep()函数功能:该函数对于指定的时间间隔挂起当前的执行线程。函数原型:void Sleep(DWORD dwMilliseco n
33、ds);参数:dwMilliseconds :定义挂起执行线程的时间,以毫秒为单位。取值为 0时,该线程 将余下的时间片交给处于就绪状态的同一优先级的其他线程。若没有处于就绪状态的同一优先 级的其他线程,则函数立即返回,该线程继续执行。若取值为INFINITE则造成无限延迟。返回值:该函数没有返回值。备注:一个线程可以在调用该函数时将睡眠时间设为0毫秒,以将剩余的时间片交出。使用Sleep函数和直接或间接创建窗口的代码时必须非常小心。若线程创建了窗口,它就必须处理消息。消息广播被发送给系统中的所有窗口。若有一个线程调用Sleep函数时使用了无限延迟,则系统会死锁。两个直接创建窗口的代码的例子是
34、DDE和COM Colnitialize 。因此,若有一个创建窗口的线程,则使用 MsgWaitForMutipleObjects 和 MsgWaitForMutipleObjectsEx 函数,而不 使用Sleep()函数。432 ReleaseMutex()函数功能:该函数放弃指定互斥对象的拥有权。函数原型:BOOL ReleaseMutex(HANDLE hMutex)参数:hMutex:互斥对象句柄。为 CreateMutex或OpenMutex函数的返回值。返回值:如果函数调用成功,那么返回值是非零值;如果函数调用失败,那么返回值是零 值。若想获得更多错误信息,请调用 GetLast
35、Error函数。备注:如果调用线程不拥有互斥对象,ReleaseMutex函数失败。一个线程通过调用等待函数拥有互斥对象。创建该互斥对象的线程也拥有互斥对象,而不 需要调用等待函数。当互斥对象的所有者线程不再需要互斥对象时,它可以调用ReleaseMutex函数。当一个线程拥有一个互斥对象后,它可以用该互斥对象多次调用等待函数而不会阻塞。这 防止一个线程等待一个它已拥有的互斥对象时出现死锁。不过,为了释放所有权,该线程必须 为每一个等待操作调用一次 ReleaseMutex函数。433 WaitForSi ngleObject函数功能:当如下情况之一发生时该函数返回:指定对象处于信号态;超时。
36、函数原型:DWORD WaitForSingleObject( HANDLE hHandle,DWORD dwMilliseconds);参数:hHandle:等待对象句柄。若想了解指定句柄的对象类型列表,参阅下面说明部分。 在WndowsN中,句柄必须有SYNCHRONIZE问权限。若想获得更多的信息,请查看Standard Access Rights。dwMilliseconds :指定以毫秒为单位的超时间隔。如果超时,即使对象的状态是非信号态 的并且没有完成,函数也返回。如果 dwMilliseconds是0,函数测试对象的状态并立刻返回: 如果dwMillseconds是INFINlT
37、E,函数从不超时。返回值:如果函数调用成功,返回值表明引起函数返回的事件。可能值如下: WAIT_ABANDONE指定对象是互斥对象,在线程被终止前,线程没有释放互斥对象。互斥 对象的所属关系被授予调用线程,并且该互斥对象被置为非信号态。WAIT_OBJECT_0指定对象的状态被置为信号态。 WAIT_TIMEOUT超时,并且对象的状态为非信号态。如果函数调用失败,返回值是 WAIT_FAILED若想获得更多错误信息,请调用 GetLastError函 数。4.3.4 GetHead函数功能:用来获取代表此列表中的头兀素的指针函数原型:CTypedPtrList:GetHead参数:指定保存在
38、列表中的元素类型的模板参数返回值:如果是通过一个指向con st CTypedPtrList的指针访问此列表,贝U GetHead返回一个类型由模板参数TYPE旨定的指针。这使此函数只能被使用在赋值语句的右边,这样就保护 了列表不被修改。如果列表被直接访问,或通过一个指向CTypedPtrList的指针访问,则GetHead返回对一个类型由模板参数TYPE旨定的指针的引用。这使得此函数可以使用在赋值语句的任何一边,从而允 许该列表可以被修改四. 程序主要源码清单由于代码比较多,在此我给出生产者一消费者中核心部分调试好,可以运行的源码,如果要完整代码,请查看本程序原整的原代码/ MultiThr
39、eadDIg.cpp : implementation file#include "stdafx.h"#in clude "MultiThread.h"#in clude "MultiThreadDlg.h"#in clude "afxtempl.h"#i nclude "afxmt.h"#i nclude "time.h"#include "stdio.h"#i nclude "stdlib.h"#i nclude "win
40、 base.h" volatile int threadC on troller;volatile int check;volatile HANDLE hMutex;CListvCStri ng,CStri ng&> list;CListBox *pbox1,*pbox2,*pbox3,*pbox4,*pbox5; int nu mber;#ifdef _DEBUG#defi ne new DEBUG_NEW#un def THIS_FILEstatic char THIS_FILE = _FILE_;#en dif/class CObject;/ CAboutDIg
41、dialog used for App Aboutclass CAboutDlg : public CDialog/初始化消息句柄public:CAboutDlg();enum IDD = IDD_ABOUTBOX ;protected:virtual void DoDataExcha nge(CDataExcha nge* pDX); / Impleme ntatio n protected:DECLARE_MESSAGE_MAP();void CAboutDlg:DoDataExcha nge(CDataExcha nge* pDX)CDialog:DoDataExcha nge(pDX)
42、;BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)END_MESSAGE_MAP()/CMultiThreadDlg:CMultiThreadDlg(CWnd* pPare nt /*=NULL*/):CDialog(CMultiThreadDlg:IDD, pPare nt)m_hIc on = AfxGetApp()->LoadIco n( IDR_MAINFRAME);void CMultiThreadDlg:DoDataExcha nge(CDataExcha nge* pDX)CDialog:DoDataExcha nge(pDX);BEGIN_MES
43、SAGE_MAP(CMultiThreadDlg, CDialog)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_START, On Start)ON_BN_CLICKED(IDC_STOP, On Stop)END_MESSAGE_MAP()/BOOL CMultiThreadDlg:O nlni tDialog()创建线程CDialog:O nlni tDialog();ASSERT(IDM_ABOUTBOX & OxFFFO) = IDM_ABOUTBOX);ASSERT(IDM_ABO
44、UTBOX < 0xF000);CMe nu* pSysMe nu = GetSystemMe nu(FALSE);if (pSysMe nu != NULL)CStri ng strAboutMe nu;strAboutMe nu.LoadStri ng(IDS_ABOUTBOX);if QstrAboutMe nu.lsEmpty()pSysMe nu->Appe ndMe nu(MF_SEPARATOR);pSysMe nu->Appe ndMe nu(MF_STRING, IDM_ABOUTBOX, strAboutMe nu);/获取对话框中子窗口控件的句柄pbox
45、1=(CListBox*)GetDlgltem(IDC_LIST1);pbox2=(CListBox*)GetDlgltem(IDC_LIST2);pbox3=(CListBox*)GetDlgltem(IDC_LIST3);pbox4=(CListBox*)GetDlgltem(IDC_LIST4);pbox5=(CListBox*)GetDlgltem(IDC_LIST5);nu mber=0;return TRUE; / return TRUE交出控制权void CMultiThreadDlg:O nSysComma nd(UINT nID, LPARAM lParam)/获取控制命令i
46、f (n ID & OxFFFO) = IDM_ABOUTBOX)CAboutDIg dlgAbout;dlgAbout.DoModal();elseCDialog:O nSysComma nd( nID, IParam);/窗体显示大小void CMultiThreadDlg:O nPai nt()if (IsIco nic()CPai ntDC dc(this); / device con text for paintingSen dMessage(WMCONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);int cxIcon = GetSyste
47、mMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClie ntRect(& rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIc on + 1) / 2;dc.DrawIc on(x, y, m_hIc on);elseCDialog:O nPa in t();HCURSOR CMultiThreadDlg:O nQueryDraglco n()return (HCURSOR) m_hIc
48、o n;void CMultiThreadDlg:O nStart() / 开始创建线程hMutex=CreateMutex(NULL,FALSE,NULL); 初始化threadC on troller=1;check=TRUE;HWND hWnd=GetSafeHw nd();/得到控制权AfxBegi nThread(ThreadProc,hWnd,THREAD_PRIORITY_NORMAL)启用生产者线程 1(P1)AfxBeginThread(ThreadProc2,hWnd,THREAD_PRIORITY_NORMAL)启用生产者线程 2(P2)AfxBeginThread(Th
49、readProc3,hWnd,THREAD_PRIORITY_NORMAL)启用生产者线程 3(P3)AfxBegi nThread(Thread_co nsumer,hWnd,THREAD_PRIORITY_NORMAL)启用消费者线程1(S1)AfxBegi nThread(Thread_co nsumer2,hWnd,THREAD_PRIORITY_NORMAL)启用消费者线程2(S2)void CMultiThreadDlg:O nStop()双击暂时停止所有工作threadC on troller=0;check=FALSE;UINT CMultiThreadDlg:ThreadPr
50、oc(LPVOID param)/ 生产者 1 的生产过程while(threadC on troller)WaitForSi ngleObject(hMutex,INFINITE);等待一个同步事件的到来if(n umber<20)srand (u nsig ned)time(NULL);/返回一个随机数int n;n=rand()%9+1;随机显示字数Sleep( n*100);CStri ng str;CStri ng str_;for(i nt i=0; i<n; i+)循环随机的字数str_.Format("%c",65+ra nd()%9+1);显示
51、大写字母str.I nsert(i,str_);插入成一列list .AddTail(CStri ng(str);CStri ng stri ng;strin g.Format("%s%d%s%d","Oxaa", n, list.GetTail(),sizeof(list.GetTail()Asizeof(n); 按格式消息头(1B,固定为Oxaa),消息长度(1B),消息内容(nB),校验和(1B)pbox1->AddStri ng(stri ng);/打印nu mber+;ReleaseMutex(hMutex);/ 释放互斥return 0
52、;UINT CMultiThreadDlg:ThreadProc2(LPVOID param)while(threadC on troller)WaitForSi ngleObject(hMutex,INFINITE);if(n umber<20)sran d (un sig ned)time(NULL);int n;n=ran d()%9+1;Sleep( n*100);CStri ng str;CStri ng str_;for(i nt i=0; i<n; i+)str_.Format("%c",97+ra nd()%9+1);str.l nsert(i,
53、str_);list .AddTail(CStri ng(str);CStri ng stri ng;strin g.Format("%s%d%s%d","Oxaa", n, list.GetTail(),sizeof(list.GetTail()Asizeof(n);pbox2->AddStri ng(stri ng);nu mber+;ReleaseMutex(hMutex);return 0;UINT CMultiThreadDlg:ThreadProc3(LPVOID param)while(threadC on troller)WaitForSi ngleObject(hMutex,INFINITE);等待一个同步事件的到来if(n umber<20)srand (u nsig ned)time(NULL);/返回一个随机数int n;n=ran d()%9+1;Sleep( n*100);CStri ng str;CStri ng str_;for(i nt i=0; i<n; i+)str_.Format("%c",48+ra nd()%9+1);str.I nsert(i,str_);list .AddTail(CStri ng(str);CStri
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 统编版语文六年级上册 第三单元 习作-让生活更美好 +公开课一等奖创新教学设计
- 备战2026年高考高中语文必修下课文中的文化常识梳理
- 先兆流产教学课件
- 电缆计量规则解读
- 恒星脉动观测数据-洞察及研究
- 转个人公积金办理合同5篇
- 内控管理提升课件设计
- 元音字母e的课件
- 内容生产加工安全培训课件
- 创业团队的组建课件
- 以资抵账管理办法
- 护士长笔试题库及答案
- 2025年辅警招聘考试试题库(含答案)
- 精神运动康复
- 2025年陕西省中考数学试题卷(含答案详解)
- 2025年中小学生国防知识竞赛题库及答案
- 机械制图选择题试题库及答案
- 湖南省科技创新惠企助企政策汇编 2025
- DB45∕T 2746-2023 国家储备林培育技术规程
- 医保基金监管培训课件
- 药厂变更管理培训
评论
0/150
提交评论