??xml version="1.0" encoding="utf-8" standalone="yes"?>国产精品一久久香蕉国产线看,97久久天天综合色天天综合色hd,亚洲精品无码久久久久去q http://www.shnenglu.com/suiaiguo/category/11253.html天行健,君子以自Z息; 地势坤,君子以厚徯?/description>zh-cnFri, 24 Jul 2009 15:21:26 GMTFri, 24 Jul 2009 15:21:26 GMT60多线E编E浅析(3Q——多U程的互斥与同步http://www.shnenglu.com/suiaiguo/archive/2009/07/24/91045.htmlSagaSagaFri, 24 Jul 2009 07:14:00 GMThttp://www.shnenglu.com/suiaiguo/archive/2009/07/24/91045.htmlhttp://www.shnenglu.com/suiaiguo/comments/91045.htmlhttp://www.shnenglu.com/suiaiguo/archive/2009/07/24/91045.html#Feedback0http://www.shnenglu.com/suiaiguo/comments/commentRss/91045.htmlhttp://www.shnenglu.com/suiaiguo/services/trackbacks/91045.htmlU程同步是指U程之间所h的一U制U关p,一个线E的执行依赖另一个线E的消息Q当它没有得到另一个线E的消息时应{待Q直到消息到达时才被唤醒?br>U程互斥是指对于׃n的进E系l资源,在各单个U程讉K时的排它性。当有若q个U程都要使用某一׃n资源ӞM时刻最多只允许一个线E去使用Q其它要使用该资源的U程必须{待Q直到占用资源者释放该资源。线E互斥可以看成是一U特D的U程同步Q下文统UCؓ同步Q?br>
U程间的同步Ҏ大体可分Zc:用户模式和内核模式。顾名思义Q内核模式就是指利用pȝ内核对象的单一性来q行同步Q用时需要切换内核态与用户态,而用h式就是不需要切换到内核态,只在用户态完成操作?br>用户模式下的Ҏ有:原子操作Q例如一个单一的全局变量Q,临界区。内核模式下的方法有Q事Ӟ信号量,互斥量?br>下面我们来分别看一下这些方法:

原子操作Q全局变量Q:
#include "stdafx.h"
#include 
"windows.h"
#include 
"stdio.h"

volatile int ThreadData = 1;

void ThreadProcess()
{
    
for(int i=0; i<6; i++)
    
{
        Sleep(
1000);
        printf(
"Sub  Thread Tick %5d!\n",(i+1)*1000);
    }

    ThreadData 
= 0;
    printf(
"Exit Sub Thread!\n");

}


int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE hThread;
    DWORD ThreadID;
    hThread
=CreateThread(NULL,
        
0,
        (LPTHREAD_START_ROUTINE)ThreadProcess,
        NULL,
        
0,
        
&ThreadID);

    
while (ThreadData)
    
{
        printf(
"Main Thread is waiting for Sub Thread!\n");
        Sleep(
600);
    }


    printf(
"Main Thread Finished! \n");
    system(
"pause");
    
return 0;
}

   在上面的E序中,我利用了全局变量ThreadData来进行线E间的同步,当子U程l束时改变该|而父U程则@环判断该值来认子线E是否已l结束,当子U程l束Ӟ父线E才l箋q行下面的操作?br>
临界区(Critical SectionQ?/strong>

保证在某一时刻只有一个线E能讉K数据的简便办法。在L时刻只允怸个线E对׃n资源q行讉K。如果有多个U程试图同时讉K临界区,那么在有一个线E进入后其他所有试图访问此临界区的U程被挂vQƈ一直持l到q入临界区的U程d。界区在被释放后,其他U程可以l箋抢占Qƈ以此辑ֈ用原子方式操作共享资源的目的?

临界区包含两个操作原语:
 EnterCriticalSectionQ) q入临界?
 LeaveCriticalSectionQ) d临界?

EnterCriticalSectionQ)语句执行后代码将q入临界Z后无论发生什么,必须保与之匚w的LeaveCriticalSectionQ)都能够被执行到。否则界区保护的共享资源将永远不会被释放。虽然界区同步速度很快Q但却只能用来同步本q程内的U程Q而不可用来同步多个进E中的线E?


事gQEventQ?/strong>
  
事g对象也可以通过通知操作的方式来保持U程的同步。ƈ且可以实C同进E中的线E同步操作?

信号量包含的几个操作原语Q?
    CreateEventQ)    创徏一个信号量
    OpenEventQ)    打开一个事?
    SetEventQ)    回置事g
    WaitForSingleObjectQ)   {待一个事?
    WaitForMultipleObjectsQ)  {待多个事g

WaitForMultipleObjects 函数原型Q?
    WaitForMultipleObjectsQ?
    IN DWORD nCount, // {待句柄?
    IN CONST HANDLE *lpHandles, //指向句柄数组
    IN BOOL bWaitAll, //是否完全{待标志
    IN DWORD dwMilliseconds //{待旉
    Q?
 
参数nCount指定了要{待的内核对象的数目Q存放这些内核对象的数组由lpHandles来指向。fWaitAllҎ定的qnCount个内核对象的两种{待方式q行了指定,为TRUE时当所有对象都被通知时函数才会返回,为FALSE则只要其中Q何一个得到通知可以返回。dwMilliseconds在这里的作用与在WaitForSingleObjectQ)中的作用是完全一致的。如果等待超Ӟ函数返回WAIT_TIMEOUT?nbsp;
  
事g可以实现不同q程中的U程同步操作Qƈ且可以方便的实现多个U程的优先比较等待操作,例如写多个WaitForSingleObject来代替WaitForMultipleObjects从而ɾ~程更加灉|?nbsp;
  
互斥量(MutexQ?/strong>
  
互斥量跟临界区很怼Q只有拥有互斥对象的U程才具有访问资源的权限Q由于互斥对象只有一个,因此决定了M情况下此׃n资源都不会同时被多个U程所讉K。当前占据资源的U程在Q务处理完后应拥有的互斥对象交出Q以便其他线E在获得后得以访问资源。互斥量比界区复杂。因Z用互斥不仅仅能够在同一应用E序不同U程中实现资源的安全׃nQ而且可以在不同应用程序的U程之间实现对资源的安全׃n?
  
    互斥量包含的几个操作原语Q?
    CreateMutexQ)    创徏一个互斥量
    OpenMutexQ)    打开一个互斥量
    ReleaseMutexQ)    释放互斥?
    WaitForMultipleObjectsQ) {待互斥量对?nbsp;
   
信号量(SemaphoresQ?/strong>

信号量对象对U程的同步方式与前面几种Ҏ不同Q信号允许多个线E同时用共享资源,q与操作pȝ中的PV操作相同。它指出了同时访问共享资源的U程最大数目。它允许多个U程在同一时刻讉K同一资源Q但是需要限制在同一时刻讉K此资源的最大线E数目。在用CreateSemaphoreQ)创徏信号量时卌同时指出允许的最大资源计数和当前可用资源计数。一般是当前可用资源计数设|ؓ最大资源计敎ͼ每增加一个线E对׃n资源的访问,当前可用资源计数׃?Q只要当前可用资源计数是大于0的,可以发Z号量信号。但是当前可用计数减到0时则说明当前占用资源的线E数已经辑ֈ了所允许的最大数目,不能在允许其他线E的q入Q此时的信号量信号将无法发出。线E在处理完共享资源后Q应在离开的同旉过ReleaseSemaphoreQ)函数当前可用资源计数加1。在M时候当前可用资源计数决不可能大于最大资源计数?

PV操作及信号量的概念都是由荷兰U学家E.W.Dijkstra提出的。信号量S是一个整敎ͼS大于{于零时代表可供q发q程使用的资源实体数Q但S于零时则表C正在等待用共享资源的q程数?

 P操作甌资源Q?
    Q?QS?Q?
    Q?Q若S?后仍大于{于Ӟ则进El执行;
    Q?Q若S?后小于零Q则该进E被d后进入与该信L对应的队列中Q然后{入进E调度?

 V操作释放资源Q?
    Q?QS?Q?
    Q?Q若相加l果大于Ӟ则进El执行;
    Q?Q若相加l果于{于Ӟ则从该信L{待队列中唤醒一个等待进E,然后再返回原q程l箋执行或{入进E调度?
  
    信号量包含的几个操作原语Q?
    CreateSemaphoreQ)  创徏一个信号量
    OpenSemaphoreQ)  打开一个信号量
    ReleaseSemaphoreQ)  释放信号?
    WaitForSingleObjectQ)  {待信号?nbsp;
   

信号量的使用特点使其更适用于对SocketQ套接字Q程序中U程的同步。例如,|络上的HTTP服务器要对同一旉内访问同一面的用h加以限制Q这时可以ؓ每一个用户对服务器的面h讄一个线E,而页面则是待保护的共享资源,通过使用信号量对U程的同步作用可以确保在M时刻无论有多用户对某一面q行讉KQ只有不大于讑֮的最大用h目的U程能够q行讉KQ而其他的讉K企图则被挂vQ只有在有用户退出对此页面的讉K后才有可能进入?nbsp;
 
因ؓ它们的用方法都很类|下面我结合v来给Z个简单的CZQ?/p>

#include "stdafx.h"
#include 
"windows.h"
#include 
"stdio.h"

volatile int ThreadData = 1;

CRITICAL_SECTION csPrint; 
// 临界?br>//HANDLE evtPrint; // 事g信号,标记事g是否已发?br>//HANDLE mtxPrint; // 互斥信号,如有信号表明已经有线E进入界区q拥有此信号
//HANDLE smphPrint; // 信号?表示是否已经辑ֈ允许的最大线E数

void Print(char *str)
{
    EnterCriticalSection(
&csPrint); // q入临界?br>    //WaitForSingleObject(evtPrint, INFINITE); // {待事g有信?br>    //WaitForSingleObject(mtxPrint, INFINITE); // {待互斥量空|(没有U程拥有它)
    
//WaitForSingleObject(smphPrint, INFINITE); // {待对共享资源请求被通过 {于 P操作 

    
for (;*str != '\0';str++)
    
{
        Sleep(
50);
        printf(
"%c",*str);
    }

    printf(
"\n");

    LeaveCriticalSection(
&csPrint); // 退Z界区
    
//SetEvent(evtPrint); // 把事件信号量恢复,变ؓ有信?br>    //ReleaseMutex(mtxPrint); // 释放对互斥量的占?br>    //ReleaseSemaphore(smphPrint, 1, NULL); // 释放׃n资源 {于 V操作 

}


void ThreadProcess()
{
    
for(int i=0; i<6; i++)
    
{
        Sleep(
1000);
        Print(
"Sub  Thread is running!");
    }

    ThreadData 
= 0;

}


int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE hThread;
    DWORD ThreadID;

    InitializeCriticalSection(
&csPrint); // 初始化界区
    
//evtPrint = CreateEvent(NULL, FALSE, TRUE, L"PrintEvent"); // 初始化事?br>    //mtxPrint = CreateMutex(NULL, FALSE, L"PrintMutex"); // 初始化互斥量
    
//smphPrint= CreateSemaphore(NULL, 1, 1, L"PrintSemaphore"); // 讄信号?个资?因此同时只可以有一个线E访?nbsp;

    hThread
=CreateThread(NULL,
        
0,
        (LPTHREAD_START_ROUTINE)ThreadProcess,
        NULL,
        
0,
        
&ThreadID);

    
while (ThreadData)
    
{
        Print(
"Main Thread is waiting for Sub Thread!");
        Sleep(
600);
    }


    printf(
"Main Thread Finished!");
    system(
"pause");
    
return 0;
}


   lg所qͼ当在同一q程中的多线E同步时Q界区是效率最最高,基本不需要什么开销。而内核对象由于要q行用户态和内核态的切换Q开销较大Q但是内核对象由于可以命名,因此它们同时可以用于q程间的同步。另外,值得一提的是,信号量可以设|允许访问资源的U程或进E个敎ͼ而不仅仅是只允许单个U程或进E访问资源?/p>

Saga 2009-07-24 15:14 发表评论
]]>
多线E中局部静态变量初始化的陷?/title><link>http://www.shnenglu.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.shnenglu.com/suiaiguo/archive/2009/07/24/91003.html</guid><wfw:comment>http://www.shnenglu.com/suiaiguo/comments/91003.html</wfw:comment><comments>http://www.shnenglu.com/suiaiguo/archive/2009/07/24/91003.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/suiaiguo/comments/commentRss/91003.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/suiaiguo/services/trackbacks/91003.html</trackback:ping><description><![CDATA[<p>    C++当中常常需要一个全局唯一的对象实例,q时候,我们׃惛_单g模式。如何实现这一模式Q全局变量当然是一个简单可行的ҎQ然而,q太丑陋。嗯Q其实,丑陋倒也|了Q最严重的是它将引诱E序员滥用全局变量Q这导致维护的N?/p> <p>    既然全局变量是可能有害的Q那么,我们我们把它隐藏一下,攑ֈ某个cd中去Q作为类的静态数据成员。这看上M错,我也q么认ؓ。当我们只是单的需要一个全局对象Ӟq很好,而且_单。不q,天空中尚有一朵小的乌云Q让我们来看一看它是什么?/p> <p>    静态成员变量的初始化,和全局对象一P实际上是在main函数q入后,我们写下的第一行代码之前被执行的。而且Q我们知道那个著名的初始化顺序不可靠的问题(跨编译单元)。当我的全局对象是一个复杂对象――这很常见,比如一个环境管理器――它甚至q需要复杂的装配q程Q我们需要考虑Q构个单件的时候,其对象都准备好了吗?如果我们不能定Q那么一个常见的措施是gq单件对象的构造――把它gq到全局对象初始化结束以后怎么Pq好像很Ҏ实现Q?/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.shnenglu.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.shnenglu.com/Images/OutliningIndicators/ContractedBlock.gif" align=top><span style="COLOR: #000000">SomeClass </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> SomeClass ::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.shnenglu.com/Images/dot.gif"></span><span id=Codehighlighter1_34_76_Open_Text><span style="COLOR: #000000">{ <br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> SomeClass inst;<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">inst;<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div> <p>不错吧?它不但可以gq到全局对象初始化之后,甚至可以延迟到有人需要它的时候,才被构造出来,随需应变Q呵呵,是不是很帅?嗯,q有一点小问题Q不仅存在对象初始化序问题Q析构也同样存在问题。局部静态变量的析构Q和全局对象一P是在main函数退出前q行的,如果也要考虑序问题的话...是不是有炚w烦呢Q?/p> <p>    q度设计是一U罪Q我是不是考虑的太复杂了?如果压根׃需要考虑析构序Q这是不是很完美的解x案?没那么简单!非但不够完美Q而且Q这里面仍然存在~陷Q当我们q行在多U程环境的时候,静态变量的初始化来实现单gQ是不可靠的――直接的_静态变量有可能初始化多ơ!在作实验之前Q我们现分析一下静态局部变量的实现方式Q下面是前面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.shnenglu.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.shnenglu.com/Images/OutliningIndicators/ContractedBlock.gif" align=top><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (</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.shnenglu.com/Images/dot.gif"></span><span id=Codehighlighter1_17_63_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top> initialized </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">true</span><span style="COLOR: #000000">;<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> (</span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">inst)SomeClass;<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">inst;</span></div> <p>每个静态变量都会拥有自q初始化与否的标志Q静态变量初始化q不是一个原子操作,也没有ؓ多线E而设立互斥区QC++语言本n是没有线E概늚Q,因此Q我们要惛_现多U程下的单g延迟创徏Q就不得不解决重复初始化的问题。至于如何实玎ͼ实际上这斚w的代码很多了。一个显然的Ҏ是设立互斥区Q传l的双检技术可以有效解册一问题――至目前的C++是这P至于最q在csdn看到在Java中双失效的文章Q我认ؓ应该由Java语言负责?/p> <p>    其实Q局部静态变量可能多ơ初始化Qƈ不难理解Q实践上Q也很少Z重的问题――出问题的条件还是挺苛刻的:多线E,不可多次初始化,恰好多个U程同时调用Q恰好在if之后发生U程调度。很出问题Q不{于不出问题Q特别的Q对于广泛用的应用E序来说Q出错概率就不是一点点了。写q篇东西的原因,是今天在公司看到的一D代码,作了标识W替换:</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.shnenglu.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.shnenglu.com/Images/OutliningIndicators/ContractedBlock.gif" align=top><span style="COLOR: #000000">SomeClass </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> 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.shnenglu.com/Images/dot.gif"></span><span id=Codehighlighter1_36_211_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top> </span><span style="COLOR: #0000ff">static</span><span style="COLOR: #000000"> CLock 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.shnenglu.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.shnenglu.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top> </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (m_pInstance </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> 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.shnenglu.com/Images/dot.gif"></span><span id=Codehighlighter1_85_188_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>  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.shnenglu.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.shnenglu.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>  </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> (m_pInstance </span><span style="COLOR: #000000">==</span><span style="COLOR: #000000"> 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.shnenglu.com/Images/dot.gif"></span><span id=Codehighlighter1_130_166_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>   m_pInstance </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> SomeClass;<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>  }</span></span><span style="COLOR: #000000"><br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>  g_lock.Unlock();<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top> }</span></span><span style="COLOR: #000000"><br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top> </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> m_pInstance;<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif" align=top></span></div> <p>pD代码,虽然知道用双,且不说Lock/Unlock可以更好的处理,static CLock g_lockҎ是错误。锁本n可能被初始化多次Q象q种资源cd的对象,多次构造几乎肯定会出错的。而对于单件模式的实现Q我认ؓQ一般而言QLoki:: SingletonHolder会是一个好的选择?/p> <p> </p> <p>本文出处Q?a >http://blog.csdn.net/wingfiring/archive/2005/10/09/498242.aspx</a></p> <img src ="http://www.shnenglu.com/suiaiguo/aggbug/91003.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/suiaiguo/" target="_blank">Saga</a> 2009-07-24 10:47 <a href="http://www.shnenglu.com/suiaiguo/archive/2009/07/24/91003.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多线E编E浅析(2Q——线E间通信http://www.shnenglu.com/suiaiguo/archive/2009/07/23/90940.htmlSagaSagaThu, 23 Jul 2009 09:18:00 GMThttp://www.shnenglu.com/suiaiguo/archive/2009/07/23/90940.htmlhttp://www.shnenglu.com/suiaiguo/comments/90940.htmlhttp://www.shnenglu.com/suiaiguo/archive/2009/07/23/90940.html#Feedback0http://www.shnenglu.com/suiaiguo/comments/commentRss/90940.htmlhttp://www.shnenglu.com/suiaiguo/services/trackbacks/90940.html   上文我们介绍了如何徏立一个简单的多线E程序,多线E之间不可避免的需要进行通信。相比于q程间通信来说Q线E间通信无疑是相Ҏ较简单的?/p>

   首先我们来看看最单的ҎQ那是使用全局变量Q静态变量也可以Q来q行通信Q由于属于同一个进E的各个U程是处于同一个进E空间中的,q且它们׃nq个q程的各U资源,因此它们都可以毫无障的讉Kq个q程中的全局变量。当需要有多个U程来访问一个全局变量Ӟ通常我们会在q个全局变量前加上volatile声明Q来告诉~译器这个全局变量是易变的Q让~译器不要对q个变量q行优化Q至于编译器到底有没有按照你的要求来对volatileq行处理q个暂且不理Q?/p>

   下面贴出一D늮单的CZ代码Q?/p>

#include "stdafx.h"
#include 
"windows.h"
#include 
"stdio.h"

volatile int ThreadData = 0;

void ThreadProcess()
{
    
for(int i=0; i<6; i++)
    
{
        ThreadData 
+= 1000;
        Sleep(
1000);
        printf(
"Sub  Thread Tick %5d! %5d\n",(i+1)*1000, ThreadData);
    }

    printf(
"Exit Sub Thread!\n");
    
}


int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE hThread;
    DWORD ThreadID;
    hThread
=CreateThread(NULL,
                     
0,
                     (LPTHREAD_START_ROUTINE)ThreadProcess,
                     NULL,
                     
0,
                     
&ThreadID);
    
    
for(int i=0; i<10; i++)
    
{
        ThreadData 
-= 600;
        Sleep(
600);
        printf(
"Main Thread Tick %5d! %5d\n", (i+1)*600, ThreadData);
    }

    printf(
"Main Thread Loop Finished! \n");
    system(
"pause");
    
return 0;
}

   除了全局变量之外Q还有其他的ҎQ比如利用消息机制等来实现线E间通信。这个就不详l解释了Q关于消息机Ӟ详情LWindows消息机制概述 ?nbsp;

   下面Q关于多U程中的全局变量Q我来介l点有点偏题的东西:
U程局部存储(TLSQ?/strong>
    q程中的全局变量与函数内定义的静?static)变量Q是各个U程都可以访问的׃n变量。在一个线E修改的内存内容Q对所有线E都生效。这是一个优点也是一个缺炏V说它是优点Q线E的数据交换变得非常快捷。说它是~点Q一个线E死掉了Q其它线E也性命不保; 多个U程讉K׃n数据Q需要昂늚同步开销Q也Ҏ造成同步相关的BUG?br>  如果需要在一个线E内部的各个函数调用都能讉K、但其它U程不能讉K的变量(被称为static memory local to a thread U程局部静态变量)Q就需要新的机制来实现。这是TLS?br>  U程局部存储在不同的^台有不同的实玎ͼ可移植性不太好。 
  Ҏ一Q每个线E创建时pȝl它分配一个LPVOID指针的数l(叫做TLS数组Q,q个数组从C~程角度是隐藏着的不能直接访问,需要通过一些C API函数调用讉K。首先定义一些DWORDU程全局变量或函数静态变?准备作ؓ各个U程讉K自己的TLS数组的烦引变量。一个线E用TLSӞW一步在U程内调用TlsAlloc()函数Qؓ一个TLS数组索引变量与这个线E的TLS数组的某个槽(slotQ关联v来,例如获得一个烦引变量:
  global_dwTLSindex=TLSAlloc();
  注意Q此步之后,当前U程实际上访问的是这个TLS数组索引变量的线E内的拷贝版本。也pQ不同线E虽然看h用的是同名的TLS数组索引变量Q但实际上各个线E得到的可能是不同DWORD倹{其意义在于Q每个用TLS的线E获得了一个DWORDcd的线E局部静态变量作为TLS数组的烦引变量。C/C++原本没有直接定义U程局部静态变量的机制Q所以在如此大费周折?br>  W二步,为当前线E动态分配一块内存区域(使用LocalAlloc()函数调用Q,然后把指向这块内存区域的指针攑օTLS数组相应的槽?使用TlsValue()函数调用)?br>  W三步,在当前线E的M函数内,都可以通过TLS数组的烦引变量,使用TlsGetValue()函数得到上一步的那块内存区域的指针,然后可以进行内存区域的d操作了。这实C在一个线E内部这个范围处处可讉K的变量?br>  最后,如果不再需要上q线E局部静态变量,要动态释放掉q块内存区域(使用LocalFree()函数)Q然后从TLS数组中放弃对应的?使用TlsFree()函数Q?br>  Ҏ二:
  直接声明q个变量是各个线E有自己拯的线E局部静态变量:
  __declspec( thread ) int var_name;

Saga 2009-07-23 17:18 发表评论
]]>
多线E编E浅析(1Q——概q?/title><link>http://www.shnenglu.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.shnenglu.com/suiaiguo/archive/2009/07/23/90904.html</guid><wfw:comment>http://www.shnenglu.com/suiaiguo/comments/90904.html</wfw:comment><comments>http://www.shnenglu.com/suiaiguo/archive/2009/07/23/90904.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/suiaiguo/comments/commentRss/90904.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/suiaiguo/services/trackbacks/90904.html</trackback:ping><description><![CDATA[<p>      U程Q是在进E内部又l分的一个执行单元,他们都是由操作系l来q行划分控制的。系l创建好q程后,实际上就启动执行了该q程的主执行U程Q主执行U程以函数地址形式Q比如说main或WinMain函数Q将E序的启动点提供lWindowspȝ。主执行U程l止了,q程也就随之l止。每一个进E至有一个主执行U程Q它无需q户去d创徏Q是ql自动创建的。用h据需要在应用E序中创建其它线E,多个U程q发地运行于同一个进E中。一个进E中的所有线E都在该q程的虚拟地址I间中,共同使用q些虚拟地址I间、全局变量和系l资源,所以线E间的通讯非常方便Q多U程技术的应用也较为广泛?br> <br> 我们要操作线E,必M赖于操作pȝ提供的接口。下面我们来要介l一下操作系l提供的跟线E相关的API函数Q?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.shnenglu.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif" align=top>                 DWORD dwStackSize,<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif" align=top>                 LPTHREAD_START_ROUTINE lpStartAddress,<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif" align=top>                 LPVOID lpParameter,<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif" align=top>                 DWORD dwCreationFlags,<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif" align=top>                 LPDWORD lpThreadId);</span></div> <p>该函数在其调用进E的q程I间里创Z个新的线E,q返回已建线E的句柄Q其中各参数说明如下Q?br>lpThreadAttributesQ指向一?SECURITY_ATTRIBUTES l构的指针,该结构决定了U程的安全属性,一般置?NULLQ?<br>dwStackSizeQ指定了U程的堆栈深度,一般都讄?Q?<br>lpStartAddressQ表C新U程开始执行时代码所在函数的地址Q即U程的v始地址。一般情况ؓ(LPTHREAD_START_ROUTINE)ThreadProcessQThreadProcess 是线E函数名Q?<br>lpParameterQ指定了U程执行时传送给U程?2位参敎ͼ即线E函数的参数Q?<br>dwCreationFlagsQ控制线E创建的附加标志Q可以取两种倹{如果该参数?Q线E在被创建后׃立即开始执行;如果该参CؓCREATE_SUSPENDED,则系l生线E后Q该U程处于挂v状态,q不马上执行Q直臛_数ResumeThread被调用; <br>lpThreadIdQ该参数q回所创徏U程的IDQ?<br>如果创徏成功则返回线E的句柄Q否则返回NULL?</p> <p> </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.shnenglu.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">DWORD SuspendThread(HANDLE hThread);</span></div> <p>该函数用于挂h定的U程Q如果函数执行成功,则线E的执行被终止?/p> <p> </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.shnenglu.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">DWORD ResumeThread(HANDLE hThread);</span></div> <p>该函数用于结束线E的挂v状态,执行U程?/p> <p> </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.shnenglu.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">VOID ExitThread(DWORD dwExitCode);</span></div> <p>该函数用于线E终l自w的执行Q主要在U程的执行函C被调用。其中参数dwExitCode用来讄U程的退出码?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.shnenglu.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode);</span></div> <p>一般情况下Q线E运行结束之后,U程函数正常q回Q但是应用程序可以调用TerminateThreadl止某一U程的执行。各参数含义如下Q?br>hThreadQ将被终l的U程的句柄; <br>dwExitCodeQ用于指定线E的退出码?<br>使用TerminateThread()l止某个U程的执行是不安全的Q可能会引vpȝ不稳定;虽然该函数立即终止线E的执行Q但q不释放U程所占用的资源。因此,一般不使用该函数?<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.shnenglu.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">BOOL PostThreadMessage(DWORD idThread,<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif" align=top>   UINT Msg,<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif" align=top>   WPARAM wParam,<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif" align=top>   LPARAM lParam);</span></div> <p>该函数将一条消息放入到指定U程的消息队列中Qƈ且不{到消息被该U程处理时便q回?br>idThreadQ将接收消息的线E的IDQ?<br>MsgQ指定用来发送的消息Q?<br>wParamQ同消息有关的字参数Q?<br>lParamQ同消息有关的长参数Q?<br>调用该函数时Q如果即接收消息的U程没有创徏消息循环Q则该函数执行失败?font style="BACKGROUND-COLOR: #c7edcc"></font></p> <br>下面我给Z个简单的建立U程的例子: <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.shnenglu.com/Images/OutliningIndicators/None.gif" align=top><span style="COLOR: #000000">#include </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.shnenglu.com/Images/OutliningIndicators/None.gif" align=top>#include </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.shnenglu.com/Images/OutliningIndicators/None.gif" align=top>#include </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.shnenglu.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> 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.shnenglu.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.shnenglu.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.shnenglu.com/Images/dot.gif"></span><span id=Codehighlighter1_82_207_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; i</span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">6</span><span style="COLOR: #000000">; 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.shnenglu.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.shnenglu.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>    </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.shnenglu.com/Images/dot.gif"></span><span id=Codehighlighter1_109_171_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>        Sleep(</span><span style="COLOR: #000000">1000</span><span style="COLOR: #000000">);<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>        printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Sub Thread Tick %d! \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.shnenglu.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>    }</span></span><span style="COLOR: #000000"><br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>    printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Exit Sub Thread!\n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>    <br><img src="http://www.shnenglu.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span><span style="COLOR: #000000"><br><img src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif" align=top><br><img src="http://www.shnenglu.com/Images/OutliningIndicators/None.gif" align=top></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> _tmain(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> argc, _TCHAR</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> 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.shnenglu.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.shnenglu.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.shnenglu.com/Images/dot.gif"></span><span id=Codehighlighter1_247_568_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>    HANDLE hThread;<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>    DWORD ThreadID;<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>    hThread</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">CreateThread(NULL,<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>                     </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>                     (LPTHREAD_START_ROUTINE)ThreadProcess,<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>                     NULL,<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>                     </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">,<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>                     </span><span style="COLOR: #000000">&</span><span style="COLOR: #000000">ThreadID);<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>    <br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>    </span><span style="COLOR: #0000ff">for</span><span style="COLOR: #000000">(</span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000"> i</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">; i</span><span style="COLOR: #000000"><</span><span style="COLOR: #000000">10</span><span style="COLOR: #000000">; 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.shnenglu.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.shnenglu.com/Images/OutliningIndicators/ContractedSubBlock.gif" align=top>    </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.shnenglu.com/Images/dot.gif"></span><span id=Codehighlighter1_432_494_Open_Text><span style="COLOR: #000000">{<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>        Sleep(</span><span style="COLOR: #000000">600</span><span style="COLOR: #000000">);<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>        printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Main Thread Tick %d! \n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">, i</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000">600</span><span style="COLOR: #000000">);<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>    }</span></span><span style="COLOR: #000000"><br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>    printf(</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">Main Thread Loop Finished! \n</span><span style="COLOR: #000000">"</span><span style="COLOR: #000000">);<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>    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.shnenglu.com/Images/OutliningIndicators/InBlock.gif" align=top>    </span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000"> </span><span style="COLOR: #000000">0</span><span style="COLOR: #000000">;<br><img src="http://www.shnenglu.com/Images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</span></span></div> <img src ="http://www.shnenglu.com/suiaiguo/aggbug/90904.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/suiaiguo/" target="_blank">Saga</a> 2009-07-23 11:21 <a href="http://www.shnenglu.com/suiaiguo/archive/2009/07/23/90904.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Win32应用E序中进E间通信Ҏ分析与比?/title><link>http://www.shnenglu.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.shnenglu.com/suiaiguo/archive/2009/07/21/90697.html</guid><wfw:comment>http://www.shnenglu.com/suiaiguo/comments/90697.html</wfw:comment><comments>http://www.shnenglu.com/suiaiguo/archive/2009/07/21/90697.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/suiaiguo/comments/commentRss/90697.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/suiaiguo/services/trackbacks/90697.html</trackback:ping><description><![CDATA[<p><strong>1</strong> <strong>q程与进E通信</strong></p> <p> <wbr></p> <p>  q程是装入内存ƈ准备执行的程序,每个q程都有U有的虚拟地址I间Q由代码、数据以及它可利用的pȝ资源(如文件、管道等)l成。多q程/多线E是Windows操作pȝ的一个基本特征。Microsoft Win32应用~程接口(Application Programming Interface, API)提供了大量支持应用程序间数据׃n和交换的机制Q这些机制行使的zdUCؓq程间通信(InterProcess Communication, IPC)Q进E通信是指不同进E间q行数据׃n和数据交换?br>  正因Z用Win32 APIq行q程通信方式有多U,如何选择恰当的通信方式成为应用开发中的一个重要问题,下面本文对Win32中进E通信的几U方法加以分析和比较?/p> <p> <wbr></p> <p><strong>2</strong> <strong>q程通信Ҏ</strong></p> <p><strong>2.1</strong> <strong>文g映射</strong><br>  文g映射(Memory-Mapped Files)能ɘq程把文件内容当作进E地址区间一块内存那h对待。因此,q程不必使用文gI/O操作Q只需单的指针操作可d和修Ҏ件的内容?br>  Win32 API允许多个q程讉K同一文g映射对象Q各个进E在它自q地址I间里接收内存的指针。通过使用q些指针Q不同进E就可以L修改文g的内容,实现了对文g中数据的׃n?br>  应用E序有三U方法来使多个进E共享一个文件映对象?br>  (1)l承Q第一个进E徏立文件映对象,它的子进E承该对象的句柄?br>  (2)命名文g映射Q第一个进E在建立文g映射对象时可以给该对象指定一个名?可与文g名不?。第二个q程可通过q个名字打开此文件映对象。另外,W一个进E也可以通过一些其它IPC机制(有名道、邮件槽{?把名字传l第二个q程?br>  (3)句柄复制Q第一个进E徏立文件映对象,然后通过其它IPC机制(有名道、邮件槽{?把对象句柄传递给W二个进E。第二个q程复制该句柄就取得对该文g映射对象的访问权限?br>  文g映射是在多个q程间共享数据的非常有效ҎQ有较好的安全性。但文g映射只能用于本地机器的进E之_不能用于|络中,而开发者还必须控制q程间的同步?br><strong>2.2</strong> <strong>׃n内存</strong><br>  Win32 API中共享内?Shared Memory)实际是文g映射的一U特D情c进E在创徏文g映射对象时用0xFFFFFFFF来代替文件句?HANDLE)Q就表示了对应的文g映射对象是从操作pȝ面文g讉K内存Q其它进E打开该文件映对象就可以讉K该内存块。由于共享内存是用文件映实现的Q所以它也有较好的安全性,也只能运行于同一计算Z的进E之间?br><strong>2.3</strong> <strong>匿名道</strong><br>  道(Pipe)是一U具有两个端点的通信通道Q有一端句柄的q程可以和有另一端句柄的q程通信。管道可以是单向Q一端是只读的,另一端点是只写的Q也可以是双向的一道的两端点既可M可写?br>  匿名道(Anonymous Pipe)是在父进E和子进E之_或同一父进E的两个子进E之间传输数据的无名字的单向道。通常qq程创徏道Q然后由要通信的子q程l承通道的读端点句柄或写端点句柄Q然后实现通信。父q程q可以徏立两个或更多个承匿名管道读和写句柄的子q程。这些子q程可以使用道直接通信Q不需要通过父进E?br>  匿名道是单Z实现子进E标准I/O重定向的有效ҎQ它不能在网上用,也不能用于两个不相关的进E之间?br><strong>2.4</strong> <strong>命名道</strong><br>  命名道(Named Pipe)是服务器q程和一个或多个客户q程之间通信的单向或双向道。不同于匿名道的是命名道可以在不相关的进E之间和不同计算Z间用,服务器徏立命名管道时l它指定一个名字,Mq程都可以通过该名字打开道的另一端,Ҏl定的权限和服务器进E通信?br>  命名道提供了相对简单的~程接口Q通过|络传输数据q不比同一计算Z两进E之间通信更困难,不过如果要同时和多个q程通信它就力不从心了?br><strong>2.5</strong> <strong>邮g?/strong><br>  邮g?Mailslots)提供q程间单向通信能力QQ何进E都能徏立邮件槽成ؓ邮g槽服务器。其它进E,UCؓ邮g槽客P可以通过邮g槽的名字l邮件槽服务器进E发送消息。进来的消息一直放在邮件槽中,直到服务器进E读取它为止。一个进E既可以是邮件槽服务器也可以是邮件槽客户Q因此可建立多个邮g槽实现进E间的双向通信?br>  通过邮g槽可以给本地计算Z的邮件槽、其它计机上的邮g槽或指定|络区域中所有计机上有同样名字的邮件槽发送消息。广播通信的消息长度不能超q?00字节Q非q播消息的长度则受邮件槽服务器指定的最大消息长度的限制?br>  邮g槽与命名道怼Q不q它传输数据是通过不可靠的数据?如TCP/IP协议中的UDP?完成的,一旦网l发生错误则无法保证消息正确地接Ӟ而命名管道传输数据则是徏立在可靠q接基础上的。不q邮件槽有简化的~程接口和给指定|络区域内的所有计机q播消息的能力,所以邮件槽不失为应用程序发送和接收消息的另一U选择?br><strong>2.6</strong> <strong>剪脓?/strong><br>  剪脓?Clipped Board)实质是Win32 API中一l用来传输数据的函数和消息,为Windows应用E序之间q行数据׃n提供了一个中介,Windows已徏立的剪切(复制)Q粘贴的机制Z同应用程序之间共享不同格式数据提供了一条捷径。当用户在应用程序中执行剪切或复制操作时Q应用程序把选取的数据用一U或多种格式攑֜剪脓板上。然后Q何其它应用程序都可以从剪贴板上拾取数据,从给定格式中选择适合自己的格式?br>  剪脓板是一个非常松散的交换媒介Q可以支持Q何数据格式,每一格式׃无符h数标识,Ҏ?预定?剪脓板格式,该值是Win32 API定义的常量;寚w标准格式可以使用Register Clipboard Format函数注册为新的剪贴板格式。利用剪贴板q行交换的数据只需在数据格式上一致或都可以{化ؓ某种格式p。但剪脓板只能在ZWindows的程序中使用Q不能在|络上用?br><strong>2.7</strong> <strong>动态数据交?/strong><br>  动态数据交?DDE)是用共享内存在应用E序之间q行数据交换的一U进E间通信形式。应用程序可以用DDEq行一ơ性数据传输,也可以当出现新数据时Q通过发送更新值在应用E序间动态交换数据?br>  DDE和剪贴板一h支持标准数据格式(如文本、位囄)Q又可以支持自己定义的数据格式。但它们的数据传输机制却不同Q一个明昑֌别是剪脓板操作几乎L用作对用h定操作的一ơ性应{-如从菜单中选择Paste命o。尽DDE也可以由用户启动Q但它l发挥作用一般不必用戯一步干预。DDE有三U数据交换方式:<br>  (1) 冷链Q数据交换是一ơ性数据传输,与剪贴板相同?br>  (2) 温链Q当数据交换时服务器通知客户Q然后客户必请求新的数据?br>  (3) 热链Q当数据交换时服务器自动l客户发送数据?br>  DDE交换可以发生在单机或|络中不同计机的应用程序之间。开发者还可以定义定制的DDE数据格式q行应用E序之间特别目的IPCQ它们有更紧密耦合的通信要求。大多数ZWindows的应用程序都支持DDE?br><strong>2.8</strong> <strong>对象q接与嵌?/strong><br>  应用E序利用对象q接与嵌?OLE)技术管理复合文?由多U数据格式组成的文)QOLE提供使某应用E序更容易调用其它应用程序进行数据编辑的服务。例如,OLE支持的字处理器可以嵌套电子表|当用戯~辑电子表格时OLE库可自动启动电子表格~辑器。当用户退出电子表格编辑器Ӟ该表格已在原始字处理器文档中得到更新。在q里电子表格~辑器变成了字处理器的扩展,而如果用DDEQ用戯昑ּ地启动电子表格编辑器?br>  同DDE技术相同,大多数基于Windows的应用程序都支持OLE技术?br><strong>2.9</strong> <strong>动态连接库</strong><br>  Win32动态连接库(DLL)中的全局数据通过ҎҎ可以被调用DLL的所有进E共享,q就又给q程间通信开辟了一条新的途径Q当然访问时要注意同步问题?br>  虽然可以通过DLLq行q程间数据共享,但从数据安全的角度考虑Q我们ƈ不提倡这U方法,使用带有讉K权限控制的共享内存的Ҏ更好一些?br><strong>2.10</strong> <strong>q程q程调用</strong><br>  Win32 API提供的远E过E调?RPC)使应用程序可以用远E调用函敎ͼq在网l上用RPCq行q程通信像函数调用那样单。RPC既可以在单机不同q程间用也可以在网l中使用?br>  ׃Win32 API提供的RPC服从OSF-DCE(Open Software Foundation Distributed Computing Environment)标准。所以通过Win32 API~写的RPC应用E序能与其它操作pȝ上支持DEC的RPC应用E序通信。用RPC开发者可以徏立高性能、紧密耦合的分布式应用E序?br><strong>2.11 NetBios</strong><strong>函数</strong><br>  Win32 API提供NetBios函数用于处理低|络控制Q这主要是ؓIBM NetBiospȝ~写与Windows的接口。除非那些有Ҏ低|络功能要求的应用程序,其它应用E序最好不要用NetBios函数来进行进E间通信?br><strong>2.12 Sockets</strong><br>  Windows Sockets规范是以U.C.Berkeley大学BSD UNIX中流行的Socket接口例定义的一套Windows下的|络~程接口。除了Berkeley Socket原有的库函数以外Q还扩展了一l针对Windows的函敎ͼ使程序员可以充分利用Windows的消息机制进行编E?br>  现在通过Sockets实现q程通信的网l应用越来越多,q主要的原因是Sockets的跨q_性要比其它IPC机制好得多,另外WinSock 2.0不仅支持TCP/IP协议Q而且q支持其它协?如IPX)。Sockets的唯一~点是它支持的是底层通信操作Q这使得在单机的q程间进行简单数据传递不太方便,q时使用下面介l的WM_COPYDATA消息更合适些?br><strong>2.13 WM_COPYDATA</strong><strong>消息</strong><br>  WM_COPYDATA是一U非常强大却鲜ؓ人知的消息。当一个应用向另一个应用传送数据时Q发送方只需使用调用SendMessage函数Q参数是目的H口的句柄、传递数据的起始地址、WM_COPYDATA消息。接收方只需像处理其它消息那样处理WM_COPY DATA消息Q这h发双方就实现了数据共享?br>  WM_COPYDATA是一U非常简单的ҎQ它在底层实际上是通过文g映射来实现的。它的缺Ҏ灉|性不高,q且它只能用于Windowsq_的单机环境下?/p> <p> <wbr></p> <p><strong>3</strong> <strong>l束?/strong></p> <p>  Win32 API为应用程序实现进E间通信提供了如此多U选择ҎQ那么开发者如何进行选择呢?通常在决定用哪UIPCҎ之前应考虑下一些问题,如应用程序是在网l环境下q是在单机环境下工作{?br></p> <img src ="http://www.shnenglu.com/suiaiguo/aggbug/90697.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/suiaiguo/" target="_blank">Saga</a> 2009-07-21 10:32 <a href="http://www.shnenglu.com/suiaiguo/archive/2009/07/21/90697.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.iyuhu.cn" target="_blank">þù޾Ʒ</a>| <a href="http://www.asyb.com.cn" target="_blank">þɫۺ</a>| <a href="http://www.shiweey.cn" target="_blank">Ʒþþþþþù˽</a>| <a href="http://www.gbpa.cn" target="_blank">ٸ޾þþþþ</a>| <a href="http://www.asook.cn" target="_blank">þ޾Ʒ˳ۺ </a>| <a href="http://www.tasd.org.cn" target="_blank">ŷ߽˾þ</a>| <a href="http://www.kuaijietao.cn" target="_blank">þþþƵ</a>| <a href="http://www.52galaxy.cn" target="_blank">ҹƵþþþһ </a>| <a href="http://www.hfdsbw.cn" target="_blank">ٸ޾þþþþ4</a>| <a href="http://www.fridc.cn" target="_blank">þþ91Ʒһ </a>| <a href="http://www.zqz6251.cn" target="_blank">þۺϹ׾Ʒ</a>| <a href="http://www.fengguan1688.cn" target="_blank">˳վ999þþۺ</a>| <a href="http://www.x3077.cn" target="_blank">޾ƷþþþþðĦ </a>| <a href="http://www.yueyuju.cn" target="_blank">޹뾫ƷŮ˾þþò </a>| <a href="http://www.hwwy.net.cn" target="_blank">þavרavһ</a>| <a href="http://www.fsyongli188.cn" target="_blank">91鶹Ʒ91þþ</a>| <a href="http://www.f7799.cn" target="_blank">þٸ۲AV</a>| <a href="http://www.ebianlian.cn" target="_blank">Ʒþ99</a>| <a href="http://www.biancheng88.cn" target="_blank">ŷþþҹһĻ </a>| <a href="http://www.benok.cn" target="_blank">ɫþùƷ12p</a>| <a href="http://www.zqdiary.cn" target="_blank">޾Ʒרþͬ</a>| <a href="http://www.woyaopeizi.cn" target="_blank">޾ƷþëƬ</a>| <a href="http://www.a79wvh.cn" target="_blank">þAVۺϺɫ</a>| <a href="http://www.gjvthsj.cn" target="_blank">97ȾþƵƷ99</a>| <a href="http://www.goldquote.cn" target="_blank">Ůaaaþþü</a>| <a href="http://www.zhy-gl.cn" target="_blank">ھƷþۺ88</a>| <a href="http://www.qhsy217.cn" target="_blank">Ʒþþþþþþҹ</a>| <a href="http://www.tabuluo.com.cn" target="_blank">þ777߿ۿƷ</a>| <a href="http://www.qianhongg.cn" target="_blank">99þþƷѿһ</a>| <a href="http://www.941ad.cn" target="_blank">ҹƷþþþþž</a>| <a href="http://www.gzwy9.cn" target="_blank">ԭƷ99þþƷ66</a>| <a href="http://www.shishanfz.cn" target="_blank">Ʒһþ</a>| <a href="http://www.lnboxue.cn" target="_blank">þþWWWëƬ</a>| <a href="http://www.jiyiabc.cn" target="_blank">ҹŷƷþþþþþ</a>| <a href="http://www.wasang.cn" target="_blank">þù鶹91</a>| <a href="http://www.schoenhut.com.cn" target="_blank">һɫþ88ۺպƷ</a>| <a href="http://www.pc345.cn" target="_blank">þþƷ99þ޶</a>| <a href="http://www.wshoponlinet.cn" target="_blank">ƷһþþƷ</a>| <a href="http://www.61492.cn" target="_blank">þ°Ҳȥ</a>| <a href="http://www.seo30.cn" target="_blank">99þ99þþƷƬ</a>| <a href="http://www.oq21.cn" target="_blank">þ㽶һëƬ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>