`
runfeel
  • 浏览: 904545 次
文章分类
社区版块
存档分类
最新评论

多线程同步:互斥对象、事件对象、关键代码段

 
阅读更多
互斥对象、事件对象、关键代码段
<wbr>一、互斥对象和事件对象属于内核对象,利用内核对象进行线程同步,速度较慢,但<strong>可以实现在多个进程中各线程间进行同步</strong>。 <p><wbr><wbr><wbr><wbr>二、关键代码段式工作在用户方式下,同步速度较快,但在使用关键代码段时,很容易进入死锁状态,因为在进入关键代码时无法设定超时值。</wbr></wbr></wbr></wbr></p> <p><wbr><wbr><wbr><wbr>MFC下InitializeCriticalSectio<wbr><wbr>n()和DeleteCriticalSection()可以放在类的构造函数和析构函数中</wbr></wbr></wbr></wbr></wbr></wbr></p> <p><strong><wbr><wbr><wbr><wbr>在编写程序时首选关键代码段,但需要非常注意死锁问题!</wbr></wbr></wbr></wbr></strong></p> <p><wbr><wbr><wbr><wbr><wbr>多线程编程推荐书籍《Windows核心编程》机械工业出版社</wbr></wbr></wbr></wbr></wbr></p> <p>三、线程、进程、程序的区别</p> <p><span style="font-family:宋体"><wbr><wbr></wbr></wbr></span></p> <table border="1" cellspacing="0" cellpadding="0"><tbody> <tr> <td> <p><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>程序</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> </td> <td> <p>计算机指令的集合,它以文件的形式存储在磁盘上</p> </td> </tr> <tr> <td> <p><wbr><wbr><wbr><wbr><wbr><wbr><wbr>进程</wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> </td> <td> <p>通常被定义为一个正在运行的程序的实例,是一个程序在其自身的地址空间中的一次执行活动</p> </td> </tr> </tbody></table> <p><span style="font-family:宋体">区别:<span style="color:#ff0000">进程是资源申请、调度和独立运行的单位,因此,它使用系统中的运行资源;而程序不能申请系统资源,不能被系统调度,也不能作为独立的运行的单位</span>, <wbr>因此,他不占用系统的运行资源。</wbr></span></p> <div> <ul><li>进程由两个部分组成: </li></ul> </div> <p><wbr>1、操作系统用来管理进程的内核对象。内核对象是操作系统内部分配的一个内存块,内核对象也是系统用来存放关于进程的统计信息的地方。</wbr></p> <p><wbr>2、地址空间。它包含所有可执行模块或DLL模块的代码和数据。他还包含动态内存分配的空间。如线程堆栈和堆分配空间。</wbr></p> <p>内核对象:是操作系统内部分配的一个内存块,它是一种只能被内核访问的数据结构, <wbr>其成员负责维护该对象的各种信息,应用程序无法找到并直接改变它们的内容,只能通过Windows提供的函数对内核对象进行操作。</wbr></p> <ul><li>进程 </li></ul> <p><span style="color:#ff0000">进程是不活泼的。进程从来不执行任何东西,它只是线程的容器。</span></p> <p>若要使进程完成某项操作,它必须拥有一个在它的环境中运行的线程,此线程负责执行包含在进程的地址空间中的代码。</p> <p>单个进程可能包含若干个线程,这些线程都“同时”执行进程地址空间中的代码。</p> <p>每个进程至少拥有一个线程,来执行进程的地址空间中的代码。</p> <p>当创建一个进程时,操作系统会自动创建这个进程的一个线程,称为主线程。此后,该线程可以创建其他的线程</p> <ul><li>线程 </li></ul> <p>线程有两个部分组成:</p> <p><wbr>1。<span style="color:#ff0000">线程的内核对象</span>,操作系统用它来对线程实施管理,内核对象也是系统用来存放线程统计信息的地方。</wbr></p> <p><wbr>2。<span style="color:#ff0000">线程堆栈</span>,它用于维护线程在执行代码时需要的所有参数和局部变量。</wbr></p> <p>当创建线程时,系统创建一个线程内核对象。</p> <p>该线程内核对象不是线程本身,而是操作系统用来管理线程的较小的数据结构。</p> <p>可以将线程内核对象视为由关于线程的统计信息组成的一个小型数据结构。</p> <p>线程总是在某个进程环境中创建。</p> <p>系统从进程的地址空间中分配内存,供线程的堆栈使用。</p> <p>新线程运行的进程环境与创建线程的环境相同。</p> <p>因此,新线程可以访问进程的内核对象的所有句柄、进程中的所有内存和在这个相同的进程中的所有其他线程的堆栈。这使得单个进程中的多个线程确实能够非常容易的互相通信。</p> <p>线程只有一个内核对象和一个堆栈,保留的记录很少,因此所需要的内存也很少。</p> <p>因为线程需要的开销比进程少,因此在编程中经常采用多线程来解决编程问题,而尽量避免创建新的进程。</p> <ul><li>线程运行 </li></ul> <p>对于单个CPU</p> <p>操作系统为每一个运行线程安排一定的CPU时间——时间片。</p> <p>系统通过一种循环的方式为线程提供时间片,线程在自己的时间内运行,因时间片相当短,因此,给用户的感觉,就好像线程是同时进行的一样。</p> <p>如果计算机拥有多个CPU,线程就能真正意义上运行了</p> <ul><li>注意 </li></ul> <p><wbr>我们可以用多进程代替多线程,但是这样不是明智的,因为</wbr></p> <p><wbr>1.每新建一个进程,系统要为之分配4GB的虚拟内存,浪费资源;而多线程共享同一个地址空间,占用资源较少</wbr></p> <p><wbr>2.在进程之间发生切换时,要交换整个地址空间;而线程之间的切换只是执行环境的改变,效率较高。 <wbr></wbr></wbr></p> <p><wbr><wbr><wbr><wbr><wbr><wbr><wbr>四、多线程具体实现</wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p><strong>一、互斥对象</strong></p> <p>这种办法不适合在多核CPU的电脑上 。自动重置(只有一个线程可以得到事件对象)<br> #include<br> #include</p> <p>DWORD WINAPI Fun1Proc (LPVOID lpParameter);<br> DWORD WINAPI Fun2Proc (LPVOID lpParameter);</p> <p>int index=0;<br> int tickets=100;<br> HANDLE hMutex;<br> void main()<br> {<br><wbr><wbr>HANDLE hThread1,hThread2;<br><wbr><wbr>hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);<br><wbr><wbr>hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);<br><wbr><wbr>CloseHandle(hThread1); <wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>//关闭句柄没有终止线程,标示主线程对新线程的引用不感兴趣,引用计数减1<br><wbr><wbr>CloseHandle(hThread2);<br><wbr><br><wbr><wbr>//创建互斥对象<br><wbr><wbr>hMutex=CreateMutex(NULL,FALSE,NULL); <wbr>//FALSE标示该线程(main)不获得互斥对象的所有权<br><wbr><wbr><br><wbr><wbr>Sleep(4000);</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p><wbr><wbr><br> }</wbr></wbr></p> <p>DWORD WINAPI Fun1Proc(LPVOID lpParameter) <wbr>//当引用计数为0时,终止线程<br> {<br><wbr><wbr><br><wbr><wbr>while (TRUE)<br><wbr><wbr>{ <wbr><br><wbr><wbr><wbr>WaitForSingleObject(hMutex,INFINITE); //INFINITE表示一直等待hMutex有效,不超时退出<br><wbr><wbr><wbr>if (tickets&gt;0)<br><wbr><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr>Sleep(2);<br><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>cout&lt;&lt;"thread1 sell tickes :"&lt;&lt;tickets--&lt;&lt;endl;<br><wbr><wbr><wbr>}<br><wbr><wbr><wbr>else<br><wbr><wbr><wbr>{</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p><wbr><wbr><wbr><wbr>break;<br><wbr><wbr><wbr>}<br><wbr><wbr><wbr>ReleaseMutex(hMutex);<br><wbr><wbr>}<br><wbr><wbr>return 0;<br> }<br> DWORD WINAPI Fun2Proc (LPVOID lpParameter)<br> {<br><wbr><wbr><wbr>while (TRUE)<br><wbr>{<br><wbr><wbr>WaitForSingleObject(hMutex,INFINITE);<br><wbr><wbr>if (tickets&gt;0)<br><wbr><wbr>{<br><wbr><wbr><wbr><br><wbr><wbr><wbr>cout&lt;&lt;"thread2 sell tickes :"&lt;&lt;tickets--&lt;&lt;endl;<br><wbr><wbr>}<br><wbr><wbr>else<br><wbr><wbr>{<br><wbr><wbr><wbr><br><wbr><wbr><wbr>break;<br><wbr><wbr>}<br><wbr><wbr>ReleaseMutex(hMutex);<br><wbr><wbr>}</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p><wbr><wbr>return 0;<br> }</wbr></wbr></p> <p><strong>二、事件对象</strong></p> <p>这种办法不适合在多核CPU的电脑上 。自动重置(只有一个线程可以得到事件对象)</p> <p>#include<br> #include</p> <p>DWORD WINAPI Fun1Proc (LPVOID lpParameter);<br> DWORD WINAPI Fun2Proc (LPVOID lpParameter);</p> <p><br> int tickets=100;<br> HANDLE g_hEvent;</p> <p>void main()<br> {<br><wbr>HANDLE hThread1,hThread2;<br><wbr>HANDLE g_hEvent1;<br><wbr>g_hEvent1=CreateEvent(NULL,FALSE,FALSE,"tickets"); <wbr><wbr>//让应用程序只能有一个实例<br><wbr>if(g_hEvent1)<br><wbr>{<br><wbr><wbr>if(ERROR_ALREADY_EXISTS==GetLastError())<br><wbr><wbr>{<br><wbr><wbr><wbr>cout&lt;&lt;"only one instance can run !"&lt;&lt;endl;<br><wbr><wbr><wbr>return;<br><wbr><wbr>}<br><wbr>}</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p><br><wbr>g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL); <wbr>//创建自动重置事件内核对象,非信号状态<br><wbr>hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);<br><wbr>hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);<br><wbr>CloseHandle(hThread1); <wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>//关闭句柄没有终止线程,标示主线程对新线程的引用不感兴趣,引用计数减1<br><wbr>CloseHandle(hThread2);<br><wbr><br><wbr>SetEvent(g_hEvent);<br><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p><wbr>Sleep(4000);<br><wbr>CloseHandle(g_hEvent);</wbr></wbr></p> <p><br> }</p> <p>DWORD WINAPI Fun1Proc(LPVOID lpParameter) <wbr>//当引用计数为0时,终止线程<br> {<br><br><wbr>while (TRUE)<br><wbr>{ <wbr><br><wbr><wbr><wbr><wbr>WaitForSingleObject(g_hEvent,INFINITE);<br><wbr><wbr>if (tickets&gt;0)<br><wbr><wbr>{<br><wbr><wbr><wbr>Sleep(2);<br><wbr><wbr><wbr>cout&lt;&lt;"thread1 sell tickes :"&lt;&lt;tickets--&lt;&lt;endl;<br><wbr><wbr>}<br><wbr><wbr>else<br><wbr><wbr>{<br><wbr><wbr><wbr><br><wbr><wbr><wbr>break;<br><wbr><wbr>}<br><wbr><wbr><wbr><wbr>SetEvent(g_hEvent);<br><wbr>}<br><wbr>return 0;<br> }<br> DWORD WINAPI Fun2Proc (LPVOID lpParameter)<br> {<br><wbr><wbr><wbr>while (TRUE)<br><wbr>{<br><wbr><wbr><wbr><wbr>WaitForSingleObject(g_hEvent,INFINITE);<br><wbr><br><wbr><wbr>if (tickets&gt;0)<br><wbr><wbr>{<br><wbr><wbr><wbr><br><wbr><wbr><wbr>cout&lt;&lt;"thread2 sell tickes :"&lt;&lt;tickets--&lt;&lt;endl;<br><wbr><wbr>}<br><wbr><wbr>else<br><wbr><wbr>{<br><wbr><wbr><wbr><br><wbr><wbr><wbr>break;<br><wbr><wbr>}<br><wbr><wbr>SetEvent(g_hEvent);<br><wbr>}<br><wbr><br><wbr>return 0;<br> }<br></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p><wbr><wbr><br><wbr></wbr></wbr></wbr></p> <wbr><wbr><wbr><wbr><p><strong><span style="color:#ff0000">三、关键代码段</span></strong></p> <p><wbr><wbr><wbr><wbr><wbr><wbr>又称为临界区:对资源的独占权。</wbr></wbr></wbr></wbr></wbr></wbr></p> <p><wbr><wbr><wbr><wbr><wbr><wbr>初始化临界区对象函数:InitializeCriticalSectio<wbr><wbr>n(EnterCriticalSection(LPCRITICAL_SECTION))参数为临界区对象;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p><wbr><wbr><wbr><wbr><wbr><wbr><wbr>申请临界区函数:EnterCriticalSection(LPCRITICAL_SECTION)参数为临界区对象;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p><wbr><wbr><wbr><wbr><wbr><wbr>释放临界区函数:LeaveCriticalSection(LPCRITICAL_SECTION)参数为临界区对象;</wbr></wbr></wbr></wbr></wbr></wbr></p> <p><wbr><wbr><wbr><wbr><wbr><wbr>释放临界区资源:DeleteCriticalSection(&amp;g_cs);</wbr></wbr></wbr></wbr></wbr></wbr></p> <p>使用关键代码段的线程同步代码:</p> <p>#include<br> #include<br> #include</p> <p>DWORD WINAPI Fun1Proc (LPVOID lpParameter);<br> DWORD WINAPI Fun2Proc (LPVOID lpParameter);</p> <p><br> int tickets=100;<br> CRITICAL_SECTION g_cs;</p> <p>void main()<br> {<br><wbr>HANDLE hThread1,hThread2;<br><wbr>HANDLE g_hEvent1;<br><wbr>g_hEvent1=CreateEvent(NULL,FALSE,FALSE,"tickets"); <wbr><wbr>//让应用程序只能有一个实例<br><wbr>if(g_hEvent1)<br><wbr>{<br><wbr><wbr>if(ERROR_ALREADY_EXISTS==GetLastError())<br><wbr><wbr>{<br><wbr><wbr><wbr>cout&lt;&lt;"only one instance can run !"&lt;&lt;endl;<br><wbr><wbr><wbr>return;<br><wbr><wbr>}<br><wbr>}<br><wbr><br><wbr>InitializeCriticalSectio<wbr><wbr>n(&amp;g_cs); <wbr><wbr><span style="color:#ff0000">//必须在创建线程之前初始化临界区对象,否则会出错<br></span><wbr><br><wbr>// <wbr>g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL); <wbr>//创建自动重置事件内核对象,非信号状态<br><wbr>hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);<br><wbr>hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);<br><wbr>CloseHandle(hThread1); <wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>//关闭句柄没有终止线程,标示主线程对新线程的引用不感兴趣,引用计数减1<br><wbr>CloseHandle(hThread2);<br><wbr><br><wbr>// <wbr>SetEvent(g_hEvent);<br><wbr><br><wbr><br> // <wbr>getchar();<br><wbr>Sleep(4000);<br><wbr>DeleteCriticalSection(&amp;g_cs);<br><wbr>getchar();<br><wbr>// <wbr>CloseHandle(g_hEvent);<br><wbr><br><wbr><br> }</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p>DWORD WINAPI Fun1Proc(LPVOID lpParameter) <wbr>//当引用计数为0时,终止线程<br> {</wbr></p> <p><wbr>while (TRUE)<br><wbr>{ <wbr><br><wbr><wbr>EnterCriticalSection(&amp;g_cs);<br><wbr><wbr><br><wbr><wbr>if (tickets&gt;0)<br><wbr><wbr>{<br><wbr><wbr><wbr>Sleep(2);<br><wbr><wbr><wbr>cout&lt;&lt;"thread1 sell tickes :"&lt;&lt;tickets--&lt;&lt;endl;<br><wbr><wbr><wbr>LeaveCriticalSection(&amp;g_cs);<br><wbr><wbr>}<br><wbr><wbr>else<br><wbr><wbr>{<br><wbr><wbr><wbr>LeaveCriticalSection(&amp;g_cs);<br><wbr><wbr><wbr>break;<br><wbr><wbr>}<br><wbr><wbr><br><wbr>}<br><wbr>return 0;<br> }<br> DWORD WINAPI Fun2Proc (LPVOID lpParameter)<br> {<br><wbr><wbr><wbr>while (TRUE)<br><wbr>{<br><wbr><wbr><br><wbr><wbr>EnterCriticalSection(&amp;g_cs);<br><wbr><wbr>if (tickets&gt;0)<br><wbr><wbr>{<br><wbr><wbr><wbr><br><wbr><wbr><wbr>cout&lt;&lt;"thread2 sell tickes :"&lt;&lt;tickets--&lt;&lt;endl;<br><wbr><wbr><wbr><wbr><wbr>LeaveCriticalSection(&amp;g_cs);<br><wbr><wbr>}<br><wbr><wbr>else<br><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr>LeaveCriticalSection(&amp;g_cs);<br><wbr><wbr><wbr>break;<br><wbr><wbr>}<br><wbr><wbr><br><wbr>}<br><wbr><br><wbr>return 0;<br> }</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p><span style="color:#ff0000">三、线程死锁问题:</span></p> <p>#include<br> #include<br> #include</p> <p>DWORD WINAPI Fun1Proc (LPVOID lpParameter);<br> DWORD WINAPI Fun2Proc (LPVOID lpParameter);</p> <p><br> int tickets=100;<br> CRITICAL_SECTION g_csA;<br> CRITICAL_SECTION g_csB;<br> void main()<br> {<br><wbr>HANDLE hThread1,hThread2;<br><wbr>HANDLE g_hEvent1;<br><wbr>g_hEvent1=CreateEvent(NULL,FALSE,FALSE,"tickets"); <wbr><wbr>//让应用程序只能有一个实例<br><wbr>if(g_hEvent1)<br><wbr>{<br><wbr><wbr>if(ERROR_ALREADY_EXISTS==GetLastError())<br><wbr><wbr>{<br><wbr><wbr><wbr>cout&lt;&lt;"only one instance can run !"&lt;&lt;endl;<br><wbr><wbr><wbr>return;<br><wbr><wbr>}<br><wbr>}<br><wbr><br><wbr>InitializeCriticalSectio<wbr><wbr>n(&amp;g_csA);<br><wbr>InitializeCriticalSectio<wbr><wbr>n(&amp;g_csB);<br><wbr><br><wbr>// <wbr>g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL); <wbr>//创建自动重置事件内核对象,非信号状态<br><wbr>hThread1=CreateThread(NULL,0,Fun1Proc,NULL,0,NULL);<br><wbr>hThread2=CreateThread(NULL,0,Fun2Proc,NULL,0,NULL);<br><wbr>CloseHandle(hThread1); <wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>//关闭句柄没有终止线程,标示主线程对新线程的引用不感兴趣,引用计数减1<br><wbr>CloseHandle(hThread2);<br><wbr><br><wbr>// <wbr>SetEvent(g_hEvent);<br><wbr><br><wbr><br> // <wbr>getchar();<br><wbr>Sleep(4000);<br><wbr>DeleteCriticalSection(&amp;g_csA);<br><wbr>DeleteCriticalSection(&amp;g_csB);</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <p><wbr>// <wbr>CloseHandle(g_hEvent);<br><wbr><br><wbr><br> }</wbr></wbr></wbr></wbr></p> <p>DWORD WINAPI Fun1Proc(LPVOID lpParameter) <wbr>//当引用计数为0时,终止线程<br> {</wbr></p> <p><wbr>while (TRUE)<br><wbr>{ <wbr><br><wbr><wbr>EnterCriticalSection(&amp;g_csA);<br> // <wbr><wbr>Sleep(1);<br><wbr><wbr>EnterCriticalSection(&amp;g_csB);<br><wbr><wbr><br><wbr><wbr>if (tickets&gt;0)<br><wbr><wbr>{<br><wbr><wbr><wbr>Sleep(2);<br><wbr><wbr><wbr>cout&lt;&lt;"thread1 sell tickes :"&lt;&lt;tickets--&lt;&lt;endl;<br><wbr><wbr><wbr>LeaveCriticalSection(&amp;g_csB);<br><wbr><wbr><wbr>LeaveCriticalSection(&amp;g_csA);<br><wbr><wbr>}<br><wbr><wbr>else<br><wbr><wbr>{<br><wbr><wbr><wbr>LeaveCriticalSection(&amp;g_csB);<br><wbr><wbr><wbr>LeaveCriticalSection(&amp;g_csA);<br><wbr><wbr><wbr>break;<br><wbr><wbr>}<br><wbr><wbr><br><wbr>}<br><wbr>return 0;<br> }<br> DWORD WINAPI Fun2Proc (LPVOID lpParameter)<br> {<br><wbr><wbr><wbr>while (TRUE)<br><wbr>{<br><wbr><wbr>EnterCriticalSection(&amp;g_csB);<br><wbr>// <wbr>Sleep(1);<br><wbr><wbr>EnterCriticalSection(&amp;g_csA);<br><wbr><wbr>if (tickets&gt;0)<br><wbr><wbr>{<br><wbr><wbr><wbr><br><wbr><wbr><wbr><wbr><wbr>cout&lt;&lt;"thread2 sell tickes :"&lt;&lt;tickets--&lt;&lt;endl;<br><wbr><wbr><wbr><wbr><wbr>LeaveCriticalSection(&amp;g_csA);<br><wbr><wbr><wbr><wbr><wbr>LeaveCriticalSection(&amp;g_csB);<br><wbr><wbr>}<br><wbr><wbr>else<br><wbr><wbr>{<br><wbr><wbr><wbr><wbr><wbr>LeaveCriticalSection(&amp;g_csA);<br><wbr><wbr><wbr><wbr><wbr>LeaveCriticalSection(&amp;g_csB);<br><wbr><wbr><wbr><wbr><wbr>break;<br><wbr><wbr>}<br><wbr><wbr><br><wbr>}<br><wbr><br><wbr>return 0;<br> }</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></p> <wbr><wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>
分享到:
评论

相关推荐

    多线程代码 经典线程同步互斥问题 生产者消费者问题

    d: 经典线程同步互斥问题 e: 使用关键段解决子线程互斥问题 f: 利用事件实现线程同步问题 g: 利用互斥量来解决线程同步互斥问题 h: problem1 生产者消费者问题 (1生产者 1消费者 1缓冲区) problem1 more ...

    关于线程同步VC程序源代码

    线程同步VC源代码 关键区代码段,内核对象,多线程,互斥对象相关程序源代码

    浅谈Python线程的同步互斥与死锁

    对共享资源的操作代码段称为临界区。 影响 : 对共享资源的无序操作可能会带来数据的混乱,或者操作错误。此时往往需要同步互斥机制协调操作顺序。  3. 同步互斥机制 同步 : 同步是一种协作关系,为完成操作,多...

    Delphi多线程编程之三 同步读写全局数据

    三、还有一种用信号量对象来管理线程同步的,它是在互斥的基础上建立的,但信号量增加了资源计数的功能,预定数目的线程允许同时进入要同步的代码。有点复杂,想不到在哪可以用,现在就不研究论了。 unit Tst_...

    在同步代码结束后,使用ReleaseMutex(THandle

    三、还有一种用信号量对象来管理线程同步的,它是在互斥的基础上建立的,但信号量增加了资源计数的功能,预定数目的线程允许同时进入要同步的代码。有点复杂,想不到在哪可以用,现在就不研究论了。 发表于 @ 2008...

    详解iOS 多线程 锁 互斥 同步

    在iOS中有几种方法来解决多线程访问同一个内存地址的互斥同步问题: 方法一,@synchronized(id anObject),(最简单的方法) 会自动对参数对象加锁,保证临界区内的代码线程安全 @synchronized(self) { // 这段...

    VC++秒杀多线程,双线程读写队列数据

    摘要:VC/C++源码,系统相关,多线程同步 多线程十大经典案例之一秒杀多线程,多线程同步互斥问题《秒杀多线程第四篇一个经典的多线程同步问题》及解决多线程同步互斥的常用方法——关键段、事件、互斥量、信号量、...

    Java多线程编程 线程同步机制.docx

    锁正是基于这种思路实现的一种线程同步机制。 在对共享数据加锁后,每个线程在访问共享数据时必须先申请相应的锁。一旦获得锁后,就可以访问共享数据,并且一个锁同一时刻只能被一个线程持有,这意味着获得锁后不会...

    多线程_生产消费模型

    Windows多线程生产消费模型,应用了关键代码段,互斥量

    java关键字Synchronized详解

    ava中的关键字synchronized是一种用于实现线程同步的机制。它可以确保在同一时刻,只有一个线程能够访问被synchronized修饰的代码块或方法。这种机制可以有效地避免多线程环境下的数据竞争和不一致问题。 在Java中...

    c#多线程中Lock()关键字的用法小结

    本文介绍C# lock关键字,C#提供了一个关键字lock,它可以把一段代码定义为互斥...它可以保证当一个线程在关键代码段的时候,另一个线程不会进来,它只能等待,等到那个线程对象被释放,也就是说线程出了临界区。用法:

    操作系统课程设计生产者和消费者问题源代码

    (1)创建生产者和消费者线程 在Windows2000环境下,创建一个控制台进程,在此进程中创建n个线程来模拟生产者或者消费者。...这些同步对象在一个线程中创建,在其他线程中都可以使用,从而实现同步互斥。

    php多进程框架-模拟java多线程接口simple-fork-php.zip

    ext-sysvsem 同步互斥锁 ext-sysvshm 共享内存 特性 提供进程池 自动处理僵尸进程回收,支持无阻塞调用 提供共享内存、System V 消息队列、Semaphore...

    Java并发编程(学习笔记).xmind

    (1)如果设计正确,多线程程序可以通过提高处理器资源的利用率来提升系统吞吐率 (2)建模简单:通过使用线程可以讲复杂并且异步的工作流进一步分解成一组简单并且同步的工作流,每个工作流在一个单独的线程...

    Windows编程循序渐进.part2

    15.2 关键代码段 277 15.2.1 基本原理 277 15.2.2 实例:多线程环境下的数据共享 278 15.3 内核对象与等待函数 280 15.3.1 内核对象 280 15.3.2 等待函数 281 15.4 事件内核对象 283 15.4.1 基本原理 283 ...

    Windows编程循序渐进.part3

    15.2 关键代码段 277 15.2.1 基本原理 277 15.2.2 实例:多线程环境下的数据共享 278 15.3 内核对象与等待函数 280 15.3.1 内核对象 280 15.3.2 等待函数 281 15.4 事件内核对象 283 15.4.1 基本原理 283 ...

    HTTP代理服务器 VC实现的,源代码

    主要介绍多线程编程相关的知识,包括初始化临界段和删除临界段,使用临界段完成多个线程对临界资源的互斥访问,创建工作线程,退出工作线程,定义和设定事件,利用事件完成多个线程的同步与协作等。

    Multithreading

    多线程 流程和线程基础 流程是资源的集合。 它由过程控制块(PCB)表示。 在每个上下文切换中,特定于过程的状态都存储在PCB中,而PCB则在内存本身中。 使流程上下文切换变得昂贵的原因是: 寄存器必须存储。 ...

Global site tag (gtag.js) - Google Analytics