﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-C++ Programmer-随笔分类-MultiTask</title><link>http://www.cppblog.com/suiaiguo/category/11253.html</link><description>天行健，君子以自强不息；
地势坤，君子以厚德载物</description><language>zh-cn</language><lastBuildDate>Fri, 24 Jul 2009 15:21:26 GMT</lastBuildDate><pubDate>Fri, 24 Jul 2009 15:21:26 GMT</pubDate><ttl>60</ttl><item><title>多线程编程浅析（3）——多线程的互斥与同步</title><link>http://www.cppblog.com/suiaiguo/archive/2009/07/24/91045.html</link><dc:creator>Saga</dc:creator><author>Saga</author><pubDate>Fri, 24 Jul 2009 07:14:00 GMT</pubDate><guid>http://www.cppblog.com/suiaiguo/archive/2009/07/24/91045.html</guid><wfw:comment>http://www.cppblog.com/suiaiguo/comments/91045.html</wfw:comment><comments>http://www.cppblog.com/suiaiguo/archive/2009/07/24/91045.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/suiaiguo/comments/commentRss/91045.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/suiaiguo/services/trackbacks/91045.html</trackback:ping><description><![CDATA[在进行多线程编程时，难免还要碰到两个问题，那就线程间的互斥与同步：<br>线程同步是指线程之间所具有的一种制约关系，一个线程的执行依赖另一个线程的消息，当它没有得到另一个线程的消息时应等待，直到消息到达时才被唤醒。<br>线程互斥是指对于共享的进程系统资源，在各单个线程访问时的排它性。当有若干个线程都要使用某一共享资源时，任何时刻最多只允许一个线程去使用，其它要使用该资源的线程必须等待，直到占用资源者释放该资源。线程互斥可以看成是一种特殊的线程同步（下文统称为同步）。<br><br>线程间的同步方法大体可分为两类：用户模式和内核模式。顾名思义，内核模式就是指利用系统内核对象的单一性来进行同步，使用时需要切换内核态与用户态，而用户模式就是不需要切换到内核态，只在用户态完成操作。<br>用户模式下的方法有：原子操作（例如一个单一的全局变量），临界区。内核模式下的方法有：事件，信号量，互斥量。<br>下面我们来分别看一下这些方法：<br><br><strong>原子操作（全局变量）：</strong>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">stdafx.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">windows.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">volatile</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;ThreadData&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;ThreadProcess()<br><img id=Codehighlighter1_112_258_Open_Image onclick="this.style.display='none'; Codehighlighter1_112_258_Open_Text.style.display='none'; Codehighlighter1_112_258_Closed_Image.style.display='inline'; Codehighlighter1_112_258_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_112_258_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_112_258_Closed_Text.style.display='none'; Codehighlighter1_112_258_Open_Image.style.display='inline'; Codehighlighter1_112_258_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_112_258_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_112_258_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br><img id=Codehighlighter1_139_206_Open_Image onclick="this.style.display='none'; Codehighlighter1_139_206_Open_Text.style.display='none'; Codehighlighter1_139_206_Closed_Image.style.display='inline'; Codehighlighter1_139_206_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_139_206_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_139_206_Closed_Text.style.display='none'; Codehighlighter1_139_206_Open_Image.style.display='inline'; Codehighlighter1_139_206_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_139_206_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_139_206_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Sub&nbsp;&nbsp;Thread&nbsp;Tick&nbsp;%5d!\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,(i</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;ThreadData&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Exit&nbsp;Sub&nbsp;Thread!\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;_tmain(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;_TCHAR</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br><img id=Codehighlighter1_298_599_Open_Image onclick="this.style.display='none'; Codehighlighter1_298_599_Open_Text.style.display='none'; Codehighlighter1_298_599_Closed_Image.style.display='inline'; Codehighlighter1_298_599_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_298_599_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_298_599_Closed_Text.style.display='none'; Codehighlighter1_298_599_Open_Image.style.display='inline'; Codehighlighter1_298_599_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_298_599_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_298_599_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hThread;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;ThreadID;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;hThread</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">CreateThread(NULL,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(LPTHREAD_START_ROUTINE)ThreadProcess,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ThreadID);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(ThreadData)<br><img id=Codehighlighter1_457_529_Open_Image onclick="this.style.display='none'; Codehighlighter1_457_529_Open_Text.style.display='none'; Codehighlighter1_457_529_Closed_Image.style.display='inline'; Codehighlighter1_457_529_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_457_529_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_457_529_Closed_Text.style.display='none'; Codehighlighter1_457_529_Open_Image.style.display='inline'; Codehighlighter1_457_529_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_457_529_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_457_529_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Main&nbsp;Thread&nbsp;is&nbsp;waiting&nbsp;for&nbsp;Sub&nbsp;Thread!\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">600</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Main&nbsp;Thread&nbsp;Finished!&nbsp;\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;system(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">pause</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<p>&nbsp;&nbsp;&nbsp;在上面的程序中，我利用了全局变量ThreadData来进行线程间的同步，当子线程结束时改变该值，而父线程则循环判断该值来确认子线程是否已经结束，当子线程结束时，父线程才继续进行下面的操作。<br><br><strong>临界区（Critical Section）</strong> </p>
<p>保证在某一时刻只有一个线程能访问数据的简便办法。在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区，那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起，并一直持续到进入临界区的线程离开。临界区在被释放后，其他线程可以继续抢占，并以此达到用原子方式操作共享资源的目的。 </p>
<p>临界区包含两个操作原语：<br>&nbsp;EnterCriticalSection（） 进入临界区 <br>&nbsp;LeaveCriticalSection（） 离开临界区 </p>
<p>EnterCriticalSection（）语句执行后代码将进入临界区以后无论发生什么，必须确保与之匹配的LeaveCriticalSection（）都能够被执行到。否则临界区保护的共享资源将永远不会被释放。虽然临界区同步速度很快，但却只能用来同步本进程内的线程，而不可用来同步多个进程中的线程。 </p>
<p><br><strong>事件（Event）</strong> <br>&nbsp;&nbsp; <br>事件对象也可以通过通知操作的方式来保持线程的同步。并且可以实现不同进程中的线程同步操作。 </p>
<p>信号量包含的几个操作原语： <br>&nbsp; 　　CreateEvent（） &nbsp;&nbsp;&nbsp;创建一个信号量 <br>&nbsp; 　　OpenEvent（） &nbsp;&nbsp;&nbsp;打开一个事件 <br>&nbsp; 　　SetEvent（） &nbsp;&nbsp;&nbsp;回置事件 <br>&nbsp; 　　WaitForSingleObject（） &nbsp;&nbsp;等待一个事件 <br>&nbsp; 　　WaitForMultipleObjects（）　&nbsp;等待多个事件 </p>
<p>WaitForMultipleObjects 函数原型： <br>&nbsp; 　　WaitForMultipleObjects（ <br>&nbsp; 　　IN DWORD nCount, // 等待句柄数 <br>&nbsp; 　　IN CONST HANDLE *lpHandles, //指向句柄数组 <br>&nbsp; 　　IN BOOL bWaitAll, //是否完全等待标志 <br>&nbsp; 　　IN DWORD dwMilliseconds //等待时间 <br>&nbsp; 　　） <br>&nbsp;<br>参数nCount指定了要等待的内核对象的数目，存放这些内核对象的数组由lpHandles来指向。fWaitAll对指定的这nCount个内核对象的两种等待方式进行了指定，为TRUE时当所有对象都被通知时函数才会返回，为FALSE则只要其中任何一个得到通知就可以返回。dwMilliseconds在这里的作用与在WaitForSingleObject（）中的作用是完全一致的。如果等待超时，函数将返回WAIT_TIMEOUT。&nbsp;<br>&nbsp;&nbsp; <br>事件可以实现不同进程中的线程同步操作，并且可以方便的实现多个线程的优先比较等待操作，例如写多个WaitForSingleObject来代替WaitForMultipleObjects从而使编程更加灵活。&nbsp;<br>&nbsp;&nbsp; <br><strong>互斥量（Mutex）</strong> <br>&nbsp;&nbsp; <br>互斥量跟临界区很相似，只有拥有互斥对象的线程才具有访问资源的权限，由于互斥对象只有一个，因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。当前占据资源的线程在任务处理完后应将拥有的互斥对象交出，以便其他线程在获得后得以访问资源。互斥量比临界区复杂。因为使用互斥不仅仅能够在同一应用程序不同线程中实现资源的安全共享，而且可以在不同应用程序的线程之间实现对资源的安全共享。 <br>&nbsp;&nbsp; <br>&nbsp; 　　互斥量包含的几个操作原语： <br>&nbsp; 　　CreateMutex（） &nbsp;&nbsp; 创建一个互斥量 <br>&nbsp; 　　OpenMutex（） &nbsp;&nbsp; 打开一个互斥量 <br>&nbsp; 　　ReleaseMutex（） &nbsp;&nbsp; 释放互斥量 <br>&nbsp; 　　WaitForMultipleObjects（） 等待互斥量对象&nbsp;<br>&nbsp;&nbsp;&nbsp;<br><strong>信号量（Semaphores）</strong> </p>
<p>信号量对象对线程的同步方式与前面几种方法不同，信号允许多个线程同时使用共享资源，这与操作系统中的PV操作相同。它指出了同时访问共享资源的线程最大数目。它允许多个线程在同一时刻访问同一资源，但是需要限制在同一时刻访问此资源的最大线程数目。在用CreateSemaphore（）创建信号量时即要同时指出允许的最大资源计数和当前可用资源计数。一般是将当前可用资源计数设置为最大资源计数，每增加一个线程对共享资源的访问，当前可用资源计数就会减1，只要当前可用资源计数是大于0的，就可以发出信号量信号。但是当前可用计数减小到0时则说明当前占用资源的线程数已经达到了所允许的最大数目，不能在允许其他线程的进入，此时的信号量信号将无法发出。线程在处理完共享资源后，应在离开的同时通过ReleaseSemaphore（）函数将当前可用资源计数加1。在任何时候当前可用资源计数决不可能大于最大资源计数。 </p>
<p>PV操作及信号量的概念都是由荷兰科学家E.W.Dijkstra提出的。信号量S是一个整数，S大于等于零时代表可供并发进程使用的资源实体数，但S小于零时则表示正在等待使用共享资源的进程数。 </p>
<p>&nbsp;P操作申请资源： <br>&nbsp; 　　（1）S减1； <br>&nbsp; 　　（2）若S减1后仍大于等于零，则进程继续执行； <br>&nbsp; 　　（3）若S减1后小于零，则该进程被阻塞后进入与该信号相对应的队列中，然后转入进程调度。 </p>
<p>&nbsp;V操作释放资源： <br>&nbsp; 　　（1）S加1； <br>&nbsp; 　　（2）若相加结果大于零，则进程继续执行； <br>&nbsp; 　　（3）若相加结果小于等于零，则从该信号的等待队列中唤醒一个等待进程，然后再返回原进程继续执行或转入进程调度。 <br>&nbsp;&nbsp; <br>&nbsp; 　　信号量包含的几个操作原语： <br>&nbsp; 　　CreateSemaphore（） &nbsp;创建一个信号量 <br>&nbsp; 　　OpenSemaphore（） &nbsp;打开一个信号量 <br>&nbsp; 　　ReleaseSemaphore（） &nbsp;释放信号量 <br>&nbsp; 　　WaitForSingleObject（） &nbsp;等待信号量&nbsp;<br>&nbsp;&nbsp;&nbsp;</p>
<p>信号量的使用特点使其更适用于对Socket（套接字）程序中线程的同步。例如，网络上的HTTP服务器要对同一时间内访问同一页面的用户数加以限制，这时可以为每一个用户对服务器的页面请求设置一个线程，而页面则是待保护的共享资源，通过使用信号量对线程的同步作用可以确保在任一时刻无论有多少用户对某一页面进行访问，只有不大于设定的最大用户数目的线程能够进行访问，而其他的访问企图则被挂起，只有在有用户退出对此页面的访问后才有可能进入。&nbsp;<br>&nbsp;<br>因为它们的使用方法都很类似，下面我结合起来给出一个简单的示例：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">stdafx.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">windows.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">volatile</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;ThreadData&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>CRITICAL_SECTION&nbsp;csPrint;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;临界区<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">HANDLE&nbsp;evtPrint;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;事件信号,标记事件是否已发生<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">HANDLE&nbsp;mtxPrint;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;互斥信号,如有信号表明已经有线程进入临界区并拥有此信号<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">HANDLE&nbsp;smphPrint;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;信号量,表示是否已经达到允许的最大线程数</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;Print(</span><span style="COLOR: #0000ff">char</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">str)<br><img id=Codehighlighter1_278_782_Open_Image onclick="this.style.display='none'; Codehighlighter1_278_782_Open_Text.style.display='none'; Codehighlighter1_278_782_Closed_Image.style.display='inline'; Codehighlighter1_278_782_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_278_782_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_278_782_Closed_Text.style.display='none'; Codehighlighter1_278_782_Open_Image.style.display='inline'; Codehighlighter1_278_782_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_278_782_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_278_782_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;EnterCriticalSection(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">csPrint);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;进入临界区<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">WaitForSingleObject(evtPrint,&nbsp;INFINITE);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;等待事件有信号<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">WaitForSingleObject(mtxPrint,&nbsp;INFINITE);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;等待互斥量空置（没有线程拥有它）<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">WaitForSingleObject(smphPrint,&nbsp;INFINITE);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;等待对共享资源请求被通过&nbsp;等于&nbsp;P操作&nbsp;</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">&nbsp;(;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">str&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">\0</span><span style="COLOR: #000000">'</span><span style="COLOR: #000000">;str</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br><img id=Codehighlighter1_543_580_Open_Image onclick="this.style.display='none'; Codehighlighter1_543_580_Open_Text.style.display='none'; Codehighlighter1_543_580_Closed_Image.style.display='inline'; Codehighlighter1_543_580_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_543_580_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_543_580_Closed_Text.style.display='none'; Codehighlighter1_543_580_Open_Image.style.display='inline'; Codehighlighter1_543_580_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_543_580_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_543_580_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">50</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">%c</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">str);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;LeaveCriticalSection(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">csPrint);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;退出临界区<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">SetEvent(evtPrint);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;把事件信号量恢复,变为有信号<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">ReleaseMutex(mtxPrint);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;释放对互斥量的占有<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">ReleaseSemaphore(smphPrint,&nbsp;1,&nbsp;NULL);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;释放共享资源&nbsp;等于&nbsp;V操作&nbsp;</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;ThreadProcess()<br><img id=Codehighlighter1_806_907_Open_Image onclick="this.style.display='none'; Codehighlighter1_806_907_Open_Text.style.display='none'; Codehighlighter1_806_907_Closed_Image.style.display='inline'; Codehighlighter1_806_907_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_806_907_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_806_907_Closed_Text.style.display='none'; Codehighlighter1_806_907_Open_Image.style.display='inline'; Codehighlighter1_806_907_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_806_907_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_806_907_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br><img id=Codehighlighter1_833_887_Open_Image onclick="this.style.display='none'; Codehighlighter1_833_887_Open_Text.style.display='none'; Codehighlighter1_833_887_Closed_Image.style.display='inline'; Codehighlighter1_833_887_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_833_887_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_833_887_Closed_Text.style.display='none'; Codehighlighter1_833_887_Open_Image.style.display='inline'; Codehighlighter1_833_887_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_833_887_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_833_887_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Print(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Sub&nbsp;&nbsp;Thread&nbsp;is&nbsp;running!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;ThreadData&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;_tmain(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;_TCHAR</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br><img id=Codehighlighter1_947_1516_Open_Image onclick="this.style.display='none'; Codehighlighter1_947_1516_Open_Text.style.display='none'; Codehighlighter1_947_1516_Closed_Image.style.display='inline'; Codehighlighter1_947_1516_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_947_1516_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_947_1516_Closed_Text.style.display='none'; Codehighlighter1_947_1516_Open_Image.style.display='inline'; Codehighlighter1_947_1516_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_947_1516_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_947_1516_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hThread;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;ThreadID;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;InitializeCriticalSection(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">csPrint);&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;初始化临界区<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">evtPrint&nbsp;=&nbsp;CreateEvent(NULL,&nbsp;FALSE,&nbsp;TRUE,&nbsp;L"PrintEvent");&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;初始化事件<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">mtxPrint&nbsp;=&nbsp;CreateMutex(NULL,&nbsp;FALSE,&nbsp;L"PrintMutex");&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;初始化互斥量<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">smphPrint=&nbsp;CreateSemaphore(NULL,&nbsp;1,&nbsp;1,&nbsp;L"PrintSemaphore");&nbsp;</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;设置信号量1个资源,因此同时只可以有一个线程访问&nbsp;</span><span style="COLOR: #008000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;hThread</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">CreateThread(NULL,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(LPTHREAD_START_ROUTINE)ThreadProcess,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ThreadID);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">while</span><span style="COLOR: #000000">&nbsp;(ThreadData)<br><img id=Codehighlighter1_1382_1450_Open_Image onclick="this.style.display='none'; Codehighlighter1_1382_1450_Open_Text.style.display='none'; Codehighlighter1_1382_1450_Closed_Image.style.display='inline'; Codehighlighter1_1382_1450_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_1382_1450_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_1382_1450_Closed_Text.style.display='none'; Codehighlighter1_1382_1450_Open_Image.style.display='inline'; Codehighlighter1_1382_1450_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_1382_1450_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_1382_1450_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Print(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Main&nbsp;Thread&nbsp;is&nbsp;waiting&nbsp;for&nbsp;Sub&nbsp;Thread!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">600</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Main&nbsp;Thread&nbsp;Finished!</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;system(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">pause</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<p><br>&nbsp;&nbsp;&nbsp;综上所述：当在同一进程中的多线程同步时，临界区是效率最最高，基本不需要什么开销。而内核对象由于要进行用户态和内核态的切换，开销较大，但是内核对象由于可以命名，因此它们同时可以用于进程间的同步。另外，值得一提的是，信号量可以设置允许访问资源的线程或进程个数，而不仅仅是只允许单个线程或进程访问资源。</p>
<img src ="http://www.cppblog.com/suiaiguo/aggbug/91045.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/suiaiguo/" target="_blank">Saga</a> 2009-07-24 15:14 <a href="http://www.cppblog.com/suiaiguo/archive/2009/07/24/91045.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程中局部静态变量初始化的陷阱</title><link>http://www.cppblog.com/suiaiguo/archive/2009/07/24/91003.html</link><dc:creator>Saga</dc:creator><author>Saga</author><pubDate>Fri, 24 Jul 2009 02:47:00 GMT</pubDate><guid>http://www.cppblog.com/suiaiguo/archive/2009/07/24/91003.html</guid><wfw:comment>http://www.cppblog.com/suiaiguo/comments/91003.html</wfw:comment><comments>http://www.cppblog.com/suiaiguo/archive/2009/07/24/91003.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/suiaiguo/comments/commentRss/91003.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/suiaiguo/services/trackbacks/91003.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; C++当中常常需要一个全局唯一的对象实例，这时候，我们就会想到单件模式。如何实现这一模式？全局变量当然是一个简单可行的方法，然而，这太丑陋。嗯，其实，丑陋倒也罢了，最严重的是它将引诱程序员滥用全局变量，这将导致维护的灾难。</p>
<p>&nbsp;&nbsp;&nbsp; 既然全局变量是可能有害的，那么，我们我们把它隐藏一下，放到某个类当中去，作为类的静态数据成员。这看上去不错，我也这么认为。当我们只是简单的需要一个全局对象时，这很好，而且足够简单。不过，天空中尚有一朵小小的乌云，让我们来看一看它是什么。</p>
<p>&nbsp;&nbsp;&nbsp; 静态成员变量的初始化，和全局对象一样，实际上是在main函数进入后，我们写下的第一行代码之前被执行的。而且，我们知道那个著名的初始化顺序不可靠的问题（跨编译单元）。当我的全局对象是一个复杂对象――这很常见，比如一个环境管理器――它甚至还需要复杂的装配过程，我们需要考虑：构建这个单件的时候，其对象都准备好了吗？如果我们不能确定，那么一个常见的措施是延迟单件对象的构造――把它延迟到全局对象初始化结束以后怎么样？这好像很容易实现：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id=Codehighlighter1_34_76_Open_Image onclick="this.style.display='none'; Codehighlighter1_34_76_Open_Text.style.display='none'; Codehighlighter1_34_76_Closed_Image.style.display='inline'; Codehighlighter1_34_76_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_34_76_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_34_76_Closed_Text.style.display='none'; Codehighlighter1_34_76_Open_Image.style.display='inline'; Codehighlighter1_34_76_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top><span style="COLOR: #000000">SomeClass&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;SomeClass&nbsp;::instance()</span><span id=Codehighlighter1_34_76_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_34_76_Open_Text><span style="COLOR: #000000">{&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;SomeClass&nbsp;inst;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">inst;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<p>不错吧？它不但可以延迟到全局对象初始化之后，甚至可以延迟到有人需要它的时候，才被构造出来，随需应变，呵呵，是不是很帅？嗯，还有一点小问题，不仅存在对象初始化顺序问题，析构也同样存在问题。局部静态变量的析构，和全局对象一样，是在main函数退出前进行的，如果也要考虑顺序问题的话...是不是有点麻烦呢？</p>
<p>&nbsp;&nbsp;&nbsp; 过度设计是一种罪，我是不是考虑的太复杂了？如果压根就不需要考虑析构顺序，这是不是很完美的解决方案？没那么简单！非但不够完美，而且，这里面仍然存在缺陷：当我们运行在多线程环境的时候，静态变量的初始化来实现单件，是不可靠的――直接的说，静态变量有可能初始化多次！在作实验之前，我们现分析一下静态局部变量的实现方式，下面是前面instance实现的伪码：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id=Codehighlighter1_17_63_Open_Image onclick="this.style.display='none'; Codehighlighter1_17_63_Open_Text.style.display='none'; Codehighlighter1_17_63_Closed_Image.style.display='inline'; Codehighlighter1_17_63_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_17_63_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_17_63_Closed_Text.style.display='none'; Codehighlighter1_17_63_Open_Image.style.display='inline'; Codehighlighter1_17_63_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">initialized)</span><span id=Codehighlighter1_17_63_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_17_63_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;initialized&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;(</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">inst)SomeClass;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">inst;</span></div>
<p>每个静态变量都会拥有自己的初始化与否的标志，静态变量初始化并不是一个原子操作，也没有为多线程而设立互斥区（C++语言本身是没有线程概念的），因此，我们要想实现多线程下的单件延迟创建，就不得不解决重复初始化的问题。至于如何实现，实际上这方面的代码很多了。一个显然的方案是设立互斥区，传统的双检测技术可以有效解决这一问题――至少目前的C++是这样，至于最近在csdn看到在Java中双检测失效的文章，我认为应该由Java语言负责。</p>
<p>&nbsp;&nbsp;&nbsp; 其实，局部静态变量可能多次初始化，并不难理解，实践上，也很少出严重的问题――出问题的条件还是挺苛刻的：多线程，不可多次初始化，恰好多个线程同时调用，恰好在if之后发生线程调度。很少出问题，不等于不出问题，特别的，对于广泛使用的应用程序来说，出错概率就不是一点点了。写这篇东西的原因，是今天在公司看到的一段代码，作了标识符替换：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img id=Codehighlighter1_36_211_Open_Image onclick="this.style.display='none'; Codehighlighter1_36_211_Open_Text.style.display='none'; Codehighlighter1_36_211_Closed_Image.style.display='inline'; Codehighlighter1_36_211_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_36_211_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_36_211_Closed_Text.style.display='none'; Codehighlighter1_36_211_Open_Image.style.display='inline'; Codehighlighter1_36_211_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top><span style="COLOR: #000000">SomeClass&nbsp;</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;SomeClass::GetInstance()</span><span id=Codehighlighter1_36_211_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_36_211_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000">&nbsp;CLock&nbsp;g_lock;<br><img id=Codehighlighter1_85_188_Open_Image onclick="this.style.display='none'; Codehighlighter1_85_188_Open_Text.style.display='none'; Codehighlighter1_85_188_Closed_Image.style.display='inline'; Codehighlighter1_85_188_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_85_188_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_85_188_Closed_Text.style.display='none'; Codehighlighter1_85_188_Open_Image.style.display='inline'; Codehighlighter1_85_188_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(m_pInstance&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;NULL)</span><span id=Codehighlighter1_85_188_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_85_188_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;g_lock.Lock();<br><img id=Codehighlighter1_130_166_Open_Image onclick="this.style.display='none'; Codehighlighter1_130_166_Open_Text.style.display='none'; Codehighlighter1_130_166_Closed_Image.style.display='inline'; Codehighlighter1_130_166_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_130_166_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_130_166_Closed_Text.style.display='none'; Codehighlighter1_130_166_Open_Image.style.display='inline'; Codehighlighter1_130_166_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;</span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(m_pInstance&nbsp;</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">&nbsp;NULL)</span><span id=Codehighlighter1_130_166_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_130_166_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;m_pInstance&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000">&nbsp;SomeClass;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;g_lock.Unlock();<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;m_pInstance;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span></div>
<p>就这段代码，虽然知道用双检测，且不说Lock/Unlock可以更好的处理，static CLock g_lock根本就是错误。锁本身可能被初始化多次，象这种资源类型的对象，多次构造几乎肯定会出错的。而对于单件模式的实现，我认为，一般而言，Loki:: SingletonHolder会是一个好的选择。</p>
<p>&nbsp;</p>
<p>本文出处：<a href="http://blog.csdn.net/wingfiring/archive/2005/10/09/498242.aspx">http://blog.csdn.net/wingfiring/archive/2005/10/09/498242.aspx</a></p>
<img src ="http://www.cppblog.com/suiaiguo/aggbug/91003.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/suiaiguo/" target="_blank">Saga</a> 2009-07-24 10:47 <a href="http://www.cppblog.com/suiaiguo/archive/2009/07/24/91003.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程编程浅析（2）——线程间通信</title><link>http://www.cppblog.com/suiaiguo/archive/2009/07/23/90940.html</link><dc:creator>Saga</dc:creator><author>Saga</author><pubDate>Thu, 23 Jul 2009 09:18:00 GMT</pubDate><guid>http://www.cppblog.com/suiaiguo/archive/2009/07/23/90940.html</guid><wfw:comment>http://www.cppblog.com/suiaiguo/comments/90940.html</wfw:comment><comments>http://www.cppblog.com/suiaiguo/archive/2009/07/23/90940.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/suiaiguo/comments/commentRss/90940.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/suiaiguo/services/trackbacks/90940.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;上文我们介绍了如何建立一个简单的多线程程序，多线程之间不可避免的需要进行通信。相比于进程间通信来说，线程间通信无疑是相对比较简单的。</p>
<p>&nbsp;&nbsp;&nbsp;首先我们来看看最简单的方法，那就是使用全局变量（静态变量也可以）来进行通信，由于属于同一个进程的各个线程是处于同一个进程空间中的，并且它们共享这个进程的各种资源，因此它们都可以毫无障碍的访问这个进程中的全局变量。当需要有多个线程来访问一个全局变量时，通常我们会在这个全局变量前加上volatile声明，来告诉编译器这个全局变量是易变的，让编译器不要对这个变量进行优化（至于编译器到底有没有按照你的要求来对volatile进行处理这个暂且不理）。</p>
<p>&nbsp;&nbsp;&nbsp;下面贴出一段简单的示例代码：</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">stdafx.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">windows.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">volatile</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;ThreadData&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;ThreadProcess()<br><img id=Codehighlighter1_112_280_Open_Image onclick="this.style.display='none'; Codehighlighter1_112_280_Open_Text.style.display='none'; Codehighlighter1_112_280_Closed_Image.style.display='inline'; Codehighlighter1_112_280_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_112_280_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_112_280_Closed_Text.style.display='none'; Codehighlighter1_112_280_Open_Image.style.display='inline'; Codehighlighter1_112_280_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_112_280_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_112_280_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br><img id=Codehighlighter1_139_244_Open_Image onclick="this.style.display='none'; Codehighlighter1_139_244_Open_Text.style.display='none'; Codehighlighter1_139_244_Closed_Image.style.display='inline'; Codehighlighter1_139_244_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_139_244_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_139_244_Closed_Text.style.display='none'; Codehighlighter1_139_244_Open_Image.style.display='inline'; Codehighlighter1_139_244_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_139_244_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_139_244_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadData&nbsp;</span><span style="COLOR: #000000">+=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Sub&nbsp;&nbsp;Thread&nbsp;Tick&nbsp;%5d!&nbsp;%5d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,(i</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">,&nbsp;ThreadData);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Exit&nbsp;Sub&nbsp;Thread!\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;_tmain(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;_TCHAR</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br><img id=Codehighlighter1_320_682_Open_Image onclick="this.style.display='none'; Codehighlighter1_320_682_Open_Text.style.display='none'; Codehighlighter1_320_682_Closed_Image.style.display='inline'; Codehighlighter1_320_682_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_320_682_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_320_682_Closed_Text.style.display='none'; Codehighlighter1_320_682_Open_Image.style.display='inline'; Codehighlighter1_320_682_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_320_682_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_320_682_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hThread;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;ThreadID;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;hThread</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">CreateThread(NULL,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(LPTHREAD_START_ROUTINE)ThreadProcess,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ThreadID);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br><img id=Codehighlighter1_505_608_Open_Image onclick="this.style.display='none'; Codehighlighter1_505_608_Open_Text.style.display='none'; Codehighlighter1_505_608_Closed_Image.style.display='inline'; Codehighlighter1_505_608_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_505_608_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_505_608_Closed_Text.style.display='none'; Codehighlighter1_505_608_Open_Image.style.display='inline'; Codehighlighter1_505_608_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_505_608_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_505_608_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadData&nbsp;</span><span style="COLOR: #000000">-=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">600</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">600</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Main&nbsp;Thread&nbsp;Tick&nbsp;%5d!&nbsp;%5d\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;(i</span><span style="COLOR: #000000">+</span><span style="COLOR: #000000">1</span><span style="COLOR: #000000">)</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">600</span><span style="COLOR: #000000">,&nbsp;ThreadData);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Main&nbsp;Thread&nbsp;Loop&nbsp;Finished!&nbsp;\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;system(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">pause</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<br>&nbsp;&nbsp;&nbsp;除了全局变量之外，还有其他的方法，比如利用消息机制等来实现线程间通信。这个就不详细解释了，关于消息机制，详情请看<a id=viewpost1_TitleUrl href="http://www.cppblog.com/suiaiguo/archive/2009/07/18/90412.html"><font color=#0066aa>Windows消息机制概述</font></a> 。&nbsp;<br><br>&nbsp;&nbsp;&nbsp;下面，关于多线程中的全局变量，我来介绍点有点偏题的东西：<br><strong>线程局部存储（TLS）</strong><br>&nbsp;&nbsp;&nbsp; 进程中的全局变量与函数内定义的静态(static)变量，是各个线程都可以访问的共享变量。在一个线程修改的内存内容，对所有线程都生效。这是一个优点也是一个缺点。说它是优点，线程的数据交换变得非常快捷。说它是缺点，一个线程死掉了，其它线程也性命不保; 多个线程访问共享数据，需要昂贵的同步开销，也容易造成同步相关的BUG。<br>　　如果需要在一个线程内部的各个函数调用都能访问、但其它线程不能访问的变量（被称为static memory local to a thread 线程局部静态变量），就需要新的机制来实现。这就是TLS。<br>　　线程局部存储在不同的平台有不同的实现，可移植性不太好。　<br>　　方法一：每个线程创建时系统给它分配一个LPVOID指针的数组（叫做TLS数组），这个数组从C编程角度是隐藏着的不能直接访问，需要通过一些C API函数调用访问。首先定义一些DWORD线程全局变量或函数静态变量,准备作为各个线程访问自己的TLS数组的索引变量。一个线程使用TLS时，第一步在线程内调用TlsAlloc()函数，为一个TLS数组索引变量与这个线程的TLS数组的某个槽(slot）关联起来，例如获得一个索引变量：<br>　　global_dwTLSindex=TLSAlloc(); <br>　　注意，此步之后，当前线程实际上访问的是这个TLS数组索引变量的线程内的拷贝版本。也就说，不同线程虽然看起来用的是同名的TLS数组索引变量，但实际上各个线程得到的可能是不同DWORD值。其意义在于，每个使用TLS的线程获得了一个DWORD类型的线程局部静态变量作为TLS数组的索引变量。C/C++原本没有直接定义线程局部静态变量的机制，所以在如此大费周折。<br>　　第二步，为当前线程动态分配一块内存区域（使用LocalAlloc()函数调用），然后把指向这块内存区域的指针放入TLS数组相应的槽中(使用TlsValue()函数调用)。<br>　　第三步，在当前线程的任何函数内，都可以通过TLS数组的索引变量，使用TlsGetValue()函数得到上一步的那块内存区域的指针，然后就可以进行内存区域的读写操作了。这就实现了在一个线程内部这个范围处处可访问的变量。<br>　　最后，如果不再需要上述线程局部静态变量，要动态释放掉这块内存区域(使用LocalFree()函数)，然后从TLS数组中放弃对应的槽(使用TlsFree()函数）。<br>　　方法二：<br>　　直接声明这个变量是各个线程有自己拷贝的线程局部静态变量：<br>　　__declspec( thread ) int var_name; 
<img src ="http://www.cppblog.com/suiaiguo/aggbug/90940.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/suiaiguo/" target="_blank">Saga</a> 2009-07-23 17:18 <a href="http://www.cppblog.com/suiaiguo/archive/2009/07/23/90940.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线程编程浅析（1）——概述</title><link>http://www.cppblog.com/suiaiguo/archive/2009/07/23/90904.html</link><dc:creator>Saga</dc:creator><author>Saga</author><pubDate>Thu, 23 Jul 2009 03:21:00 GMT</pubDate><guid>http://www.cppblog.com/suiaiguo/archive/2009/07/23/90904.html</guid><wfw:comment>http://www.cppblog.com/suiaiguo/comments/90904.html</wfw:comment><comments>http://www.cppblog.com/suiaiguo/archive/2009/07/23/90904.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/suiaiguo/comments/commentRss/90904.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/suiaiguo/services/trackbacks/90904.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;线程，是在进程内部又细分的一个执行单元，他们都是由操作系统来进行划分控制的。系统创建好进程后，实际上就启动执行了该进程的主执行线程，主执行线程以函数地址形式，比如说main或WinMain函数，将程序的启动点提供给Windows系统。主执行线程终止了，进程也就随之终止。每一个进程至少有一个主执行线程，它无需由用户去主动创建，是由系统自动创建的。用户根据需要在应用程序中创建其它线程，多个线程并发地运行于同一个进程中。一个进程中的所有线程都在该进程的虚拟地址空间中，共同使用这些虚拟地址空间、全局变量和系统资源，所以线程间的通讯非常方便，多线程技术的应用也较为广泛。<br>&nbsp;<br>&nbsp;我们要操作线程，就必须依赖于操作系统提供的接口。下面我们来简要介绍一下操作系统提供的跟线程相关的API函数：<br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">HANDLE&nbsp;CreateThread(LPSECURITY_ATTRIBUTES&nbsp;lpThreadAttributes,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwStackSize,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPTHREAD_START_ROUTINE&nbsp;lpStartAddress,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPVOID&nbsp;lpParameter,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;dwCreationFlags,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LPDWORD&nbsp;lpThreadId);</span></div>
<p>该函数在其调用进程的进程空间里创建一个新的线程，并返回已建线程的句柄，其中各参数说明如下：<br>lpThreadAttributes：指向一个 SECURITY_ATTRIBUTES 结构的指针，该结构决定了线程的安全属性，一般置为 NULL； <br>dwStackSize：指定了线程的堆栈深度，一般都设置为0； <br>lpStartAddress：表示新线程开始执行时代码所在函数的地址，即线程的起始地址。一般情况为(LPTHREAD_START_ROUTINE)ThreadProcess，ThreadProcess 是线程函数名； <br>lpParameter：指定了线程执行时传送给线程的32位参数，即线程函数的参数； <br>dwCreationFlags：控制线程创建的附加标志，可以取两种值。如果该参数为0，线程在被创建后就会立即开始执行；如果该参数为CREATE_SUSPENDED,则系统产生线程后，该线程处于挂起状态，并不马上执行，直至函数ResumeThread被调用； <br>lpThreadId：该参数返回所创建线程的ID； <br>如果创建成功则返回线程的句柄，否则返回NULL。 </p>
<p>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">DWORD&nbsp;SuspendThread(HANDLE&nbsp;hThread);</span></div>
<p>该函数用于挂起指定的线程，如果函数执行成功，则线程的执行被终止。</p>
<p>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">DWORD&nbsp;ResumeThread(HANDLE&nbsp;hThread);</span></div>
<p>该函数用于结束线程的挂起状态，执行线程。</p>
<p>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">VOID&nbsp;ExitThread(DWORD&nbsp;dwExitCode);</span></div>
<p>该函数用于线程终结自身的执行，主要在线程的执行函数中被调用。其中参数dwExitCode用来设置线程的退出码。<br>&nbsp;</p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">BOOL&nbsp;TerminateThread(HANDLE&nbsp;hThread,DWORD&nbsp;dwExitCode);</span></div>
<p>一般情况下，线程运行结束之后，线程函数正常返回，但是应用程序可以调用TerminateThread强行终止某一线程的执行。各参数含义如下：<br>hThread：将被终结的线程的句柄； <br>dwExitCode：用于指定线程的退出码。 <br>使用TerminateThread()终止某个线程的执行是不安全的，可能会引起系统不稳定；虽然该函数立即终止线程的执行，但并不释放线程所占用的资源。因此，一般不建议使用该函数。 <br></p>
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">BOOL&nbsp;PostThreadMessage(DWORD&nbsp;idThread,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;UINT&nbsp;Msg,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;WPARAM&nbsp;wParam,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;LPARAM&nbsp;lParam);</span></div>
<p>该函数将一条消息放入到指定线程的消息队列中，并且不等到消息被该线程处理时便返回。<br>idThread：将接收消息的线程的ID； <br>Msg：指定用来发送的消息； <br>wParam：同消息有关的字参数； <br>lParam：同消息有关的长参数； <br>调用该函数时，如果即将接收消息的线程没有创建消息循环，则该函数执行失败。<font style="BACKGROUND-COLOR: #c7edcc"></font></p>
<br>下面我给出一个简单的建立线程的例子：
<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">stdafx.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">windows.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top>#include&nbsp;</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">stdio.h</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000">&nbsp;ThreadProcess()<br><img id=Codehighlighter1_82_207_Open_Image onclick="this.style.display='none'; Codehighlighter1_82_207_Open_Text.style.display='none'; Codehighlighter1_82_207_Closed_Image.style.display='inline'; Codehighlighter1_82_207_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_82_207_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_82_207_Closed_Text.style.display='none'; Codehighlighter1_82_207_Open_Image.style.display='inline'; Codehighlighter1_82_207_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_82_207_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_82_207_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br><img id=Codehighlighter1_109_171_Open_Image onclick="this.style.display='none'; Codehighlighter1_109_171_Open_Text.style.display='none'; Codehighlighter1_109_171_Closed_Image.style.display='inline'; Codehighlighter1_109_171_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_109_171_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_109_171_Closed_Text.style.display='none'; Codehighlighter1_109_171_Open_Image.style.display='inline'; Codehighlighter1_109_171_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_109_171_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_109_171_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Sub&nbsp;Thread&nbsp;Tick&nbsp;%d!&nbsp;\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,i</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Exit&nbsp;Sub&nbsp;Thread!\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.cppblog.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;_tmain(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;argc,&nbsp;_TCHAR</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">&nbsp;argv[])<br><img id=Codehighlighter1_247_568_Open_Image onclick="this.style.display='none'; Codehighlighter1_247_568_Open_Text.style.display='none'; Codehighlighter1_247_568_Closed_Image.style.display='inline'; Codehighlighter1_247_568_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif" align=top><img id=Codehighlighter1_247_568_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_247_568_Closed_Text.style.display='none'; Codehighlighter1_247_568_Open_Image.style.display='inline'; Codehighlighter1_247_568_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif" align=top></span><span id=Codehighlighter1_247_568_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_247_568_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;HANDLE&nbsp;hThread;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;DWORD&nbsp;ThreadID;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;hThread</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">CreateThread(NULL,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(LPTHREAD_START_ROUTINE)ThreadProcess,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NULL,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">ThreadID);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">&lt;</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">;&nbsp;i</span><span style="COLOR: #000000">++</span><span style="COLOR: #000000">)<br><img id=Codehighlighter1_432_494_Open_Image onclick="this.style.display='none'; Codehighlighter1_432_494_Open_Text.style.display='none'; Codehighlighter1_432_494_Closed_Image.style.display='inline'; Codehighlighter1_432_494_Closed_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><img id=Codehighlighter1_432_494_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_432_494_Closed_Text.style.display='none'; Codehighlighter1_432_494_Open_Image.style.display='inline'; Codehighlighter1_432_494_Open_Text.style.display='inline';" src="http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span id=Codehighlighter1_432_494_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><img src="http://www.cppblog.com/Images/dot.gif"></span><span id=Codehighlighter1_432_494_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sleep(</span><span style="COLOR: #000000">600</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Main&nbsp;Thread&nbsp;Tick&nbsp;%d!&nbsp;\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">,&nbsp;i</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">600</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="COLOR: #000000"><br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Main&nbsp;Thread&nbsp;Loop&nbsp;Finished!&nbsp;\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;system(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">pause</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div>
<img src ="http://www.cppblog.com/suiaiguo/aggbug/90904.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/suiaiguo/" target="_blank">Saga</a> 2009-07-23 11:21 <a href="http://www.cppblog.com/suiaiguo/archive/2009/07/23/90904.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Win32应用程序中进程间通信方法分析与比较</title><link>http://www.cppblog.com/suiaiguo/archive/2009/07/21/90697.html</link><dc:creator>Saga</dc:creator><author>Saga</author><pubDate>Tue, 21 Jul 2009 02:32:00 GMT</pubDate><guid>http://www.cppblog.com/suiaiguo/archive/2009/07/21/90697.html</guid><wfw:comment>http://www.cppblog.com/suiaiguo/comments/90697.html</wfw:comment><comments>http://www.cppblog.com/suiaiguo/archive/2009/07/21/90697.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/suiaiguo/comments/commentRss/90697.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/suiaiguo/services/trackbacks/90697.html</trackback:ping><description><![CDATA[<p><strong>1</strong> <strong>进程与进程通信</strong></p>
<p>&nbsp;<wbr></p>
<p>　　进程是装入内存并准备执行的程序，每个进程都有私有的虚拟地址空间，由代码、数据以及它可利用的系统资源(如文件、管道等)组成。多进程/多线程是Windows操作系统的一个基本特征。Microsoft Win32应用编程接口(Application Programming Interface, API)提供了大量支持应用程序间数据共享和交换的机制，这些机制行使的活动称为进程间通信(InterProcess Communication, IPC)，进程通信就是指不同进程间进行数据共享和数据交换。<br>　　正因为使用Win32 API进行进程通信方式有多种，如何选择恰当的通信方式就成为应用开发中的一个重要问题，下面本文将对Win32中进程通信的几种方法加以分析和比较。</p>
<p>&nbsp;<wbr></p>
<p><strong>2</strong> <strong>进程通信方法</strong></p>
<p><strong>2.1</strong> <strong>文件映射</strong><br>　　文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待。因此，进程不必使用文件I/O操作，只需简单的指针操作就可读取和修改文件的内容。<br>　　Win32 API允许多个进程访问同一文件映射对象，各个进程在它自己的地址空间里接收内存的指针。通过使用这些指针，不同进程就可以读或修改文件的内容，实现了对文件中数据的共享。<br>　　应用程序有三种方法来使多个进程共享一个文件映射对象。<br>　　(1)继承：第一个进程建立文件映射对象，它的子进程继承该对象的句柄。<br>　　(2)命名文件映射：第一个进程在建立文件映射对象时可以给该对象指定一个名字(可与文件名不同)。第二个进程可通过这个名字打开此文件映射对象。另外，第一个进程也可以通过一些其它IPC机制(有名管道、邮件槽等)把名字传给第二个进程。<br>　　(3)句柄复制：第一个进程建立文件映射对象，然后通过其它IPC机制(有名管道、邮件槽等)把对象句柄传递给第二个进程。第二个进程复制该句柄就取得对该文件映射对象的访问权限。<br>　　文件映射是在多个进程间共享数据的非常有效方法，有较好的安全性。但文件映射只能用于本地机器的进程之间，不能用于网络中，而开发者还必须控制进程间的同步。<br><strong>2.2</strong> <strong>共享内存</strong><br>　　Win32 API中共享内存(Shared Memory)实际就是文件映射的一种特殊情况。进程在创建文件映射对象时用0xFFFFFFFF来代替文件句柄(HANDLE)，就表示了对应的文件映射对象是从操作系统页面文件访问内存，其它进程打开该文件映射对象就可以访问该内存块。由于共享内存是用文件映射实现的，所以它也有较好的安全性，也只能运行于同一计算机上的进程之间。<br><strong>2.3</strong> <strong>匿名管道</strong><br>　　管道(Pipe)是一种具有两个端点的通信通道：有一端句柄的进程可以和有另一端句柄的进程通信。管道可以是单向－一端是只读的，另一端点是只写的；也可以是双向的一管道的两端点既可读也可写。<br>　　匿名管道(Anonymous Pipe)是在父进程和子进程之间，或同一父进程的两个子进程之间传输数据的无名字的单向管道。通常由父进程创建管道，然后由要通信的子进程继承通道的读端点句柄或写端点句柄，然后实现通信。父进程还可以建立两个或更多个继承匿名管道读和写句柄的子进程。这些子进程可以使用管道直接通信，不需要通过父进程。<br>　　匿名管道是单机上实现子进程标准I/O重定向的有效方法，它不能在网上使用，也不能用于两个不相关的进程之间。<br><strong>2.4</strong> <strong>命名管道</strong><br>　　命名管道(Named Pipe)是服务器进程和一个或多个客户进程之间通信的单向或双向管道。不同于匿名管道的是命名管道可以在不相关的进程之间和不同计算机之间使用，服务器建立命名管道时给它指定一个名字，任何进程都可以通过该名字打开管道的另一端，根据给定的权限和服务器进程通信。<br>　　命名管道提供了相对简单的编程接口，使通过网络传输数据并不比同一计算机上两进程之间通信更困难，不过如果要同时和多个进程通信它就力不从心了。<br><strong>2.5</strong> <strong>邮件槽</strong><br>　　邮件槽(Mailslots)提供进程间单向通信能力，任何进程都能建立邮件槽成为邮件槽服务器。其它进程，称为邮件槽客户，可以通过邮件槽的名字给邮件槽服务器进程发送消息。进来的消息一直放在邮件槽中，直到服务器进程读取它为止。一个进程既可以是邮件槽服务器也可以是邮件槽客户，因此可建立多个邮件槽实现进程间的双向通信。<br>　　通过邮件槽可以给本地计算机上的邮件槽、其它计算机上的邮件槽或指定网络区域中所有计算机上有同样名字的邮件槽发送消息。广播通信的消息长度不能超过400字节，非广播消息的长度则受邮件槽服务器指定的最大消息长度的限制。<br>　　邮件槽与命名管道相似，不过它传输数据是通过不可靠的数据报(如TCP/IP协议中的UDP包)完成的，一旦网络发生错误则无法保证消息正确地接收，而命名管道传输数据则是建立在可靠连接基础上的。不过邮件槽有简化的编程接口和给指定网络区域内的所有计算机广播消息的能力，所以邮件槽不失为应用程序发送和接收消息的另一种选择。<br><strong>2.6</strong> <strong>剪贴板</strong><br>　　剪贴板(Clipped Board)实质是Win32 API中一组用来传输数据的函数和消息，为Windows应用程序之间进行数据共享提供了一个中介，Windows已建立的剪切(复制)－粘贴的机制为不同应用程序之间共享不同格式数据提供了一条捷径。当用户在应用程序中执行剪切或复制操作时，应用程序把选取的数据用一种或多种格式放在剪贴板上。然后任何其它应用程序都可以从剪贴板上拾取数据，从给定格式中选择适合自己的格式。<br>　　剪贴板是一个非常松散的交换媒介，可以支持任何数据格式，每一格式由一无符号整数标识，对标准(预定义)剪贴板格式，该值是Win32 API定义的常量；对非标准格式可以使用Register Clipboard Format函数注册为新的剪贴板格式。利用剪贴板进行交换的数据只需在数据格式上一致或都可以转化为某种格式就行。但剪贴板只能在基于Windows的程序中使用，不能在网络上使用。<br><strong>2.7</strong> <strong>动态数据交换</strong><br>　　动态数据交换(DDE)是使用共享内存在应用程序之间进行数据交换的一种进程间通信形式。应用程序可以使用DDE进行一次性数据传输，也可以当出现新数据时，通过发送更新值在应用程序间动态交换数据。<br>　　DDE和剪贴板一样既支持标准数据格式(如文本、位图等)，又可以支持自己定义的数据格式。但它们的数据传输机制却不同，一个明显区别是剪贴板操作几乎总是用作对用户指定操作的一次性应答－如从菜单中选择Paste命令。尽管DDE也可以由用户启动，但它继续发挥作用一般不必用户进一步干预。DDE有三种数据交换方式：<br>　　(1) 冷链：数据交换是一次性数据传输，与剪贴板相同。<br>　　(2) 温链：当数据交换时服务器通知客户，然后客户必须请求新的数据。<br>　　(3) 热链：当数据交换时服务器自动给客户发送数据。<br>　　DDE交换可以发生在单机或网络中不同计算机的应用程序之间。开发者还可以定义定制的DDE数据格式进行应用程序之间特别目的IPC，它们有更紧密耦合的通信要求。大多数基于Windows的应用程序都支持DDE。<br><strong>2.8</strong> <strong>对象连接与嵌入</strong><br>　　应用程序利用对象连接与嵌入(OLE)技术管理复合文档(由多种数据格式组成的文档)，OLE提供使某应用程序更容易调用其它应用程序进行数据编辑的服务。例如，OLE支持的字处理器可以嵌套电子表格，当用户要编辑电子表格时OLE库可自动启动电子表格编辑器。当用户退出电子表格编辑器时，该表格已在原始字处理器文档中得到更新。在这里电子表格编辑器变成了字处理器的扩展，而如果使用DDE，用户要显式地启动电子表格编辑器。<br>　　同DDE技术相同，大多数基于Windows的应用程序都支持OLE技术。<br><strong>2.9</strong> <strong>动态连接库</strong><br>　　Win32动态连接库(DLL)中的全局数据通过特殊方法可以被调用DLL的所有进程共享，这就又给进程间通信开辟了一条新的途径，当然访问时要注意同步问题。<br>　　虽然可以通过DLL进行进程间数据共享，但从数据安全的角度考虑，我们并不提倡这种方法，使用带有访问权限控制的共享内存的方法更好一些。<br><strong>2.10</strong> <strong>远程过程调用</strong><br>　　Win32 API提供的远程过程调用(RPC)使应用程序可以使用远程调用函数，这使在网络上用RPC进行进程通信就像函数调用那样简单。RPC既可以在单机不同进程间使用也可以在网络中使用。<br>　　由于Win32 API提供的RPC服从OSF-DCE(Open Software Foundation Distributed Computing Environment)标准。所以通过Win32 API编写的RPC应用程序能与其它操作系统上支持DEC的RPC应用程序通信。使用RPC开发者可以建立高性能、紧密耦合的分布式应用程序。<br><strong>2.11 NetBios</strong><strong>函数</strong><br>　　Win32 API提供NetBios函数用于处理低级网络控制，这主要是为IBM NetBios系统编写与Windows的接口。除非那些有特殊低级网络功能要求的应用程序，其它应用程序最好不要使用NetBios函数来进行进程间通信。<br><strong>2.12 Sockets</strong><br>　　Windows Sockets规范是以U.C.Berkeley大学BSD UNIX中流行的Socket接口为范例定义的一套Windows下的网络编程接口。除了Berkeley Socket原有的库函数以外，还扩展了一组针对Windows的函数，使程序员可以充分利用Windows的消息机制进行编程。<br>　　现在通过Sockets实现进程通信的网络应用越来越多，这主要的原因是Sockets的跨平台性要比其它IPC机制好得多，另外WinSock 2.0不仅支持TCP/IP协议，而且还支持其它协议(如IPX)。Sockets的唯一缺点是它支持的是底层通信操作，这使得在单机的进程间进行简单数据传递不太方便，这时使用下面将介绍的WM_COPYDATA消息将更合适些。<br><strong>2.13 WM_COPYDATA</strong><strong>消息</strong><br>　　WM_COPYDATA是一种非常强大却鲜为人知的消息。当一个应用向另一个应用传送数据时，发送方只需使用调用SendMessage函数，参数是目的窗口的句柄、传递数据的起始地址、WM_COPYDATA消息。接收方只需像处理其它消息那样处理WM_COPY DATA消息，这样收发双方就实现了数据共享。<br>　　WM_COPYDATA是一种非常简单的方法，它在底层实际上是通过文件映射来实现的。它的缺点是灵活性不高，并且它只能用于Windows平台的单机环境下。</p>
<p>&nbsp;<wbr></p>
<p><strong>3</strong> <strong>结束语</strong></p>
<p>　　Win32 API为应用程序实现进程间通信提供了如此多种选择方案，那么开发者如何进行选择呢？通常在决定使用哪种IPC方法之前应考虑下一些问题，如应用程序是在网络环境下还是在单机环境下工作等。<br></p>
<img src ="http://www.cppblog.com/suiaiguo/aggbug/90697.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/suiaiguo/" target="_blank">Saga</a> 2009-07-21 10:32 <a href="http://www.cppblog.com/suiaiguo/archive/2009/07/21/90697.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>