• 在界面线程不能使用Sleep和WaitForSingleObject之类的函数, 使用 MsgWaitForMultipleObjects


    http://blog.csdn.net/wishfly/article/details/3726985

    你在主线程用了WaitForSingleObject,导致了消息循环的阻塞,界面假死。

    然后在线程中调用了SetDlgItemText,而SetDlgItemText实际上调用的是SendMessage,

    而SendMessage要等待主线程处理完毕发送的消息才返回继续执行,

    而你主线程的消息循环已经阻塞,无法处理消息,导致整个过程“我等你,你等我”,无穷下去 

    在界面线程不能使用Sleep和WaitForSingleObject之类的函数,

    比较好的方法是,将句柄作为线程参数传递进线程,

    当线程结束后发一条消息通知主线程处理完毕

    在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)

    下面的代码我调试了将近一个星期,你能够看出什么地方出了问题吗?

    线程函数:

    DWORD WINAPI ThreadProc(
        while(!bTerminate)
        {
            // 从一个链表中读取信息并且插入到CListCtrl中
            // CListCtrl的句柄是通过线程参数传递进来的
            for(;;)
           {
               ReadInfoFromList();
               InsertToCListCtrl();
            }
        }
    }

    主线程中使用CreateThread启动线程。当想终止子线程时,在主线程中:

    bTerminate = TRUE;
    WaitForSingleObject(threadHandle, INFINITE);

    可是,以运行到WaitForSingleObject,子线程就Crash了。为什么呢?

    问题原因:

    后来我终于在InsertItem的反汇编中发现了如下的代码
    call dword ptr [__imp__SendMessageA@16 (7C141B54h)]
    可见,InsertItem是必须借助消息循环来完成任务的。

    如果我们在主线程中WaitForSingleObject了,必然导致主线程阻塞,

    也就导致了消息循环的阻塞,最终导致工作线程Crash掉了*_*

    解决方案:

    为了解决在主线程中Wait的问题,微软专门设计了一个函数MsgWaitForMultipleObjects,

    这个函数即可以等待信号(thread,event,mutex等等),也可以等待消息(MSG)。

    即不论有信号被激发或者有消息到来,此函数都可以返回。呵呵,那么我的解决办法也就出来了。

    将上面的WaitForSingleObject用下面的代码替换:

    while(TRUE)
    {
    
        DWORD result ; 
        MSG msg ; 
    
        result = MsgWaitForMultipleObjects(1, &readThreadHandle, 
            FALSE, INFINITE, QS_ALLINPUT); 
    
        if (result == (WAIT_OBJECT_0))
        {
            break;
        } 
        else 
        { 
            PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
            DispatchMessage(&msg); 
        } 
    }

    总结:

    如果在工作线程中有可能涉及到了消息驱动的API,

    那么不能在主线程中使用WaitForSingleObject一类函数,而必须使用上述的方案。

    http://www.midnightbeach.com/jon/pubs/MsgWaits/SynchedThreads_pas.html

    unit SynchedThreads;
    
    // Copyright © 1998 by Jon Shemitz, all rights reserved.
    // Permission is hereby granted to freely use, modify, and
    // distribute this source code PROVIDED that all six lines of
    // this copyright and contact notice are included without any
    // changes. Questions? Comments? Offers of work?
    // mailto:jon@midnightbeach.com - http://www.midnightbeach.com
    
    {$T+} {$hints on} {$warnings on}
    
    interface
    
    uses Windows, Classes, SysUtils, Forms;
    
    // Simple threads
    
    type
      TThreadMethod = procedure( Data : pointer ) of object;
    
      TSimpleThread = class( TThread )
      public
        constructor CreateSimple( CreateSuspended : boolean;
          _Action : TThreadMethod; _Data : pointer );
        procedure AbortThread;
      protected
        ThreadMethod : TThreadMethod;
        Data : pointer;
    
      private
        procedure Execute; override;
      end;
    
    function RunInThread( Handler : TThreadMethod; Data : pointer ) : TSimpleThread;
    
    // Wait threads (basic synchronization)
    
    procedure MsgWaitForSingleObject( Handle : THandle );
    function SpawnProcess( const Command : string ) : TProcessInformation;
    
    type
      TWaitThread = class( TSimpleThread )
      public
        constructor CreateWait( _Action : TThreadMethod; _Data : pointer );
        procedure WaitFor;
        procedure MsgWaitFor;
        procedure AbortThread;
      private
        AbortFlag : ^boolean;
        procedure Run( MsgWait : boolean );
      end;
    
    procedure WaitForThread( Handler : TThreadMethod; Data : pointer );
    procedure MsgWaitForThread( var Thread : TWaitThread; Handler : TThreadMethod;
      Data : pointer );
    
    // Stop/start threads
    
    type
      EAbortedThread = class( Exception )
      end;
    
      EThreadInUse = class( Exception )
      end;
    
      TStopStartThread = class( TSimpleThread )
      public
        Waiting : boolean;
        constructor Create;
        procedure WaitFor( _Action : TThreadMethod; _Data : pointer );
        procedure MsgWaitFor( _Action : TThreadMethod; _Data : pointer );
        procedure AbortThread;
      private
        Event : THandle;
        Aborted : boolean;
        destructor Destroy; override;
        procedure Execute; override;
        procedure Run( _Action : TThreadMethod; _Data : pointer;
          MsgWait : boolean );
      end;
    
    implementation
    
    // TSimpleThread, RunInThread
    
    constructor TSimpleThread.CreateSimple( CreateSuspended : boolean;
      _Action : TThreadMethod; _Data : pointer );
    begin
      ThreadMethod := _Action; // Set these BEFORE calling
      Data := _Data; // inherited Create()!
      FreeOnTerminate := True;
      inherited Create( CreateSuspended );
    end; // TSimpleThread.Create
    
    procedure TSimpleThread.Execute;
    begin
      ThreadMethod( Data );
    end; // TSimpleThread.Execute
    
    procedure TSimpleThread.AbortThread;
    begin
      Suspend; // // Can't kill a running thread by Freeing it
      Free; // Kills thread
    end; // TSimpleThread.AbortThread
    
    function RunInThread( Handler : TThreadMethod; Data : pointer ) : TSimpleThread;
    begin
      Result := TSimpleThread.CreateSimple( False, Handler, Data );
    end; // RunInThread
    
    // Basic synchronization
    
    procedure MsgWaitForSingleObject( Handle : THandle );
    begin
      repeat
        if MsgWaitForMultipleObjects( 1, Handle, False, INFINITE, QS_ALLINPUT )
          = WAIT_OBJECT_0 + 1 then
          Application.ProcessMessages
        else
          BREAK;
      until True = False;
    end; // MsgWaitForSingleObject
    
    function SpawnProcess( const Command : string ) : TProcessInformation;
    var
      StartupInfo : TStartupInfo;
    begin
      FillChar( StartupInfo, SizeOf( StartupInfo ), 0 ); // use defaults
      StartupInfo.cb := SizeOf( StartupInfo );
      CreateProcess( nil, PChar( Command ), nil, nil, False, 0, nil, nil,
        StartupInfo, Result );
    end; // SpawnProcess
    
    constructor TWaitThread.CreateWait( _Action : TThreadMethod; _Data : pointer );
    begin
      CreateSimple( True, _Action, _Data ); // CreateSuspended
      AbortFlag := nil;
    end; // TWaitThread.CreateWait
    
    procedure TWaitThread.WaitFor;
    begin
      Run( False );
    end; // TWaitThread.WaitFor
    
    procedure TWaitThread.MsgWaitFor;
    begin
      Run( True );
    end; // TWaitThread.MsgWaitFor
    
    procedure TWaitThread.Run( MsgWait : boolean );
    var
      Aborted : boolean;
    begin
      AbortFlag := @Aborted;
      Aborted := False;
      Resume;
      if MsgWait then
        MsgWaitForSingleObject( Handle )
      else
        inherited WaitFor;
      if Aborted then
        Abort;
    end; // TWaitThread.Run
    
    procedure TWaitThread.AbortThread;
    begin
      Assert( Assigned( AbortFlag ) );
      AbortFlag^ := True;
      inherited;
    end; // TWaitThread.CreateWait
    
    procedure WaitForThread( Handler : TThreadMethod; Data : pointer );
    begin
      TWaitThread.CreateWait( Handler, Data ).WaitFor;
    end; // WaitForThread
    
    procedure MsgWaitForThread( var Thread : TWaitThread; Handler : TThreadMethod;
      Data : pointer );
    begin
      Thread := TWaitThread.CreateWait( Handler, Data );
      Thread.MsgWaitFor;
      Thread := nil;
    end; // MsgWaitForThread
    
    // Stop/start threads
    
    constructor TStopStartThread.Create;
    begin
      Event := CreateEvent( nil, True, False, nil );
      // API call is smaller and simpler than Delphi wrapper
      Assert( Event <> NULL );
      Waiting := False;
      Aborted := False;
      inherited Create( True ); // Create a suspended thread
    end; // TStopStartThread.Create
    
    destructor TStopStartThread.Destroy;
    begin
      CloseHandle( Event );
      inherited;
    end; // TStopStartThread.Destroy
    
    procedure TStopStartThread.Execute;
    begin
      while not Terminated do
      begin
        Assert( Assigned( ThreadMethod ) );
        ThreadMethod( Data );
        SetEvent( Event );
        Suspend;
      end;
    end; // TStopStartThread.Execute
    
    procedure TStopStartThread.Run( _Action : TThreadMethod; _Data : pointer;
      MsgWait : boolean );
    begin
      if Waiting then
        raise EThreadInUse.Create( 'Thread in use' );
      if Aborted then
        raise EAbortedThread.Create( 'Aborted thread' );
    
      ThreadMethod := _Action;
      Data := _Data;
      Waiting := True;
      ResetEvent( Event );
      Resume;
      if MsgWait then
        MsgWaitForSingleObject( Event )
      else
        WaitForSingleObject( Event, INFINITE );
      Waiting := False;
      if Aborted then
        Abort; // Raise an EAbort exception
    end; // TStopStartThread.InternalRun
    
    procedure TStopStartThread.MsgWaitFor( _Action : TThreadMethod;  _Data : pointer );
    begin
      Run( _Action, _Data, True );
    end; // TStopStartThread.Run
    
    procedure TStopStartThread.WaitFor( _Action : TThreadMethod; _Data : pointer );
    begin
      Run( _Action, _Data, False );
    end; // TStopStartThread.RunBlocking
    
    procedure TStopStartThread.AbortThread;
    begin
      Suspend; // // Can't kill a running thread by Freeing it
      Aborted := True;
      SetEvent( Event );
    end; // TStopStartThread.AbortThread
    
    end.
    // Copyright (C) 2003-2009 Dolphin Project.
    
    // This program is free software: you can redistribute it and/or modify
    // it under the terms of the GNU General Public License as published by
    // the Free Software Foundation, version 2.0.
    
    // This program is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    // GNU General Public License 2.0 for more details.
    
    // A copy of the GPL 2.0 should have been included with the program.
    // If not, see http://www.gnu.org/licenses/
    
    // Official SVN repository and contact information can be found at
    // http://code.google.com/p/dolphin-emu/
    
    #include "Setup.h"
    #include "Thread.h"
    #include "Log.h"
    #ifdef SETUP_TIMER_WAITING
    #include <windows.h>
    #include "ConsoleWindow.h"
    EventCallBack FunctionPointer[ 10 ];
    #endif
    
    namespace Common
    {
    #ifdef _WIN32
    
      void InitThreading ( )
      {
        // Nothing to do in Win32 build.
      }
    
      CriticalSection::CriticalSection ( int spincount )
      {
        if ( spincount )
        {
          InitializeCriticalSectionAndSpinCount ( &section, spincount );
        }
        else
        {
          InitializeCriticalSection ( &section );
        }
      }
    
      CriticalSection::~CriticalSection ( )
      {
        DeleteCriticalSection ( &section );
      }
    
      void CriticalSection::Enter ( )
      {
        EnterCriticalSection ( &section );
      }
    
      bool CriticalSection::TryEnter ( )
      {
        return TryEnterCriticalSection ( &section ) ? true : false;
      }
    
      void CriticalSection::Leave ( )
      {
        LeaveCriticalSection ( &section );
      }
    
      Thread::Thread ( ThreadFunc function, void* arg )
        : m_hThread ( NULL ), m_threadId( 0 )
      {
        m_hThread = CreateThread ( 0, // Security attributes
          0, // Stack size
          function, arg, 0, &m_threadId );
      }
    
      Thread::~Thread ( )
      {
        WaitForDeath ( );
      }
    
      void Thread::WaitForDeath ( const int _Wait )
      {
        if ( m_hThread )
        {
          WaitForSingleObject ( m_hThread, _Wait );
          CloseHandle ( m_hThread );
          m_hThread = NULL;
        }
      }
    
      void Thread::SetAffinity ( int mask )
      {
        SetThreadAffinityMask ( m_hThread, mask );
      }
    
      void Thread::SetCurrentThreadAffinity ( int mask )
      {
        SetThreadAffinityMask ( GetCurrentThread( ), mask );
      }
    
      // Regular same thread loop based waiting
      Event::Event ( )
      {
        m_hEvent = 0;
    #ifdef SETUP_TIMER_WAITING
        DoneWaiting = false;
        StartWait = false;
        hTimer = NULL;
        hTimerQueue = NULL;
    #endif
      }
    
      void Event::Init ( )
      {
        m_hEvent = CreateEvent ( NULL, FALSE, FALSE, NULL );
      }
    
      void Event::Shutdown ( )
      {
        CloseHandle ( m_hEvent );
        m_hEvent = 0;
      }
    
      void Event::Set ( )
      {
        SetEvent ( m_hEvent );
      }
    
      void Event::Wait ( )
      {
        WaitForSingleObject ( m_hEvent, INFINITE );
      }
    
      inline HRESULT MsgWaitForSingleObject ( HANDLE handle, DWORD timeout )
      {
        return MsgWaitForMultipleObjects ( 1, &handle, FALSE, timeout, 0 );
      }
    
      void Event::MsgWait ( )
      {
        // Adapted from MSDN example http://msdn.microsoft.com/en-us/library/ms687060.aspx
        while ( true )
        {
          DWORD result;
          MSG msg;
          // Read all of the messages in this next loop,
          // removing each message as we read it.
          while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
          {
            // If it is a quit message, exit.
            if ( msg.message == WM_QUIT )
              return;
            // Otherwise, dispatch the message.
            DispatchMessage ( &msg );
          }
    
          // Wait for any message sent or posted to this queue
          // or for one of the passed handles be set to signaled.
          result = MsgWaitForSingleObject ( m_hEvent, THREAD_WAIT_TIMEOUT );
    
          // The result tells us the type of event we have.
          if ( result == ( WAIT_OBJECT_0 + 1 ) )
          {
            // New messages have arrived.
            // Continue to the top of the always while loop to
            // dispatch them and resume waiting.
            continue;
          }
          else
          {
            // result == WAIT_OBJECT_0
            // Our event got signaled
            return;
          }
        }
      }
    
      /* Separate thread timer based waiting, instead of same thread loop waiting. The downside with this
       is that it's less convenient to use because we can't stall any threads with a loop. The positive
       is that we don't cause these incredibly annoying WaitForEternity() hangings. */
    #ifdef SETUP_TIMER_WAITING
    
      /* I could not figure out how to place this in the class to, CreateTimerQueueTimer() would complain
       about some kind of type casting, anyone have any ideas about how to do it? */
      VOID CALLBACK TimerRoutine ( PVOID lpParam, BOOLEAN TimerOrWaitFired )
      {
        if ( lpParam == NULL )
        {
          DEBUG_LOG ( CONSOLE, "TimerRoutine lpParam is NULL
    " );
        }
        else
        {
          // lpParam points to the argument; in this case it is an int
    
          // DEBUG_LOG(CONSOLE, "Timer[%i] will call back
    ", *(int*)lpParam);
        }
    
        // Call back
        int Id = *( int* )lpParam;
        if ( FunctionPointer[ Id ] )
          FunctionPointer[ Id ]( );
      }
    
      // Create a timer that will call back to the calling function
      bool Event::TimerWait ( EventCallBack WaitCB, int _Id, bool OptCondition )
      {
        Id = _Id;
    
        // DEBUG_LOG(CONSOLE, "TimerWait[%i]: %i %i %i
    ", Id, StartWait, DoneWaiting, OptCondition);
    
        FunctionPointer[ Id ] = WaitCB;
    
        // This means we are done waiting, so we wont call back again, and we also reset the variables for this Event
        if ( DoneWaiting && OptCondition )
        {
          StartWait = false;
          DoneWaiting = false;
          FunctionPointer[ Id ] = NULL;
    
          // Delete all timers in the timer queue.
          if ( !DeleteTimerQueue( hTimerQueue ) )
            DEBUG_LOG ( CONSOLE, "DeleteTimerQueue failed (%d)
    ",
            GetLastError( ) );
    
          hTimer = NULL;
          hTimerQueue = NULL;
    
          return true;
        }
    
        // Else start a new callback timer
        StartWait = true;
    
        // Create the timer queue if needed
        if ( !hTimerQueue )
        {
          hTimerQueue = CreateTimerQueue ( );
          if ( NULL == hTimerQueue )
          {
            DEBUG_LOG ( CONSOLE, "CreateTimerQueue failed (%d)
    ",
            GetLastError( ) );
            return false;
          }
        }
    
        // Set a timer to call the timer routine in 10 seconds.
        if ( !CreateTimerQueueTimer( &hTimer, hTimerQueue,
          ( WAITORTIMERCALLBACK )TimerRoutine, &Id, 10, 0, 0 ) )
        {
          DEBUG_LOG ( CONSOLE, "CreateTimerQueueTimer failed (%d)
    ",
            GetLastError( ) );
          return false;
        }
    
        return false;
      }
    
      // Check if we are done or not
      bool Event::DoneWait ( )
      {
        if ( StartWait && DoneWaiting )
          return true;
        else
          return false;
      }
    
      // Tells the timer that we are done waiting
      void Event::SetTimer ( )
      {
        // We can not be done before we have started waiting
        if ( StartWait )
          DoneWaiting = true;
      }
    #endif
    
      // Supporting functions
      void SleepCurrentThread ( int ms )
      {
        Sleep ( ms );
      }
    
      typedef struct tagTHREADNAME_INFO
      {
        DWORD dwType; // must be 0x1000
        LPCSTR szName; // pointer to name (in user addr space)
        DWORD dwThreadID; // thread ID (-1=caller thread)
        DWORD dwFlags; // reserved for future use, must be zero
      } THREADNAME_INFO;
      // Usage: SetThreadName (-1, "MainThread");
      //
      // Sets the debugger-visible name of the current thread.
      // Uses undocumented (actually, it is now documented) trick.
      // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp
    
      void SetCurrentThreadName ( const TCHAR* szThreadName )
      {
        THREADNAME_INFO info;
        info.dwType = 0x1000;
    #ifdef UNICODE
        // TODO: Find the proper way to do this.
        char tname[ 256 ];
        unsigned int i;
    
        for ( i = 0; i < _tcslen( szThreadName ); i++ )
        {
          tname[ i ] = ( char )szThreadName[ i ];
          // poor man's unicode->ansi, TODO: fix
        }
    
        tname[ i ] = 0;
        info.szName = tname;
    #else
        info.szName = szThreadName;
    #endif
    
        info.dwThreadID = -1; // dwThreadID;
        info.dwFlags = 0;
        __try
        {
          RaiseException ( 0x406D1388, 0, sizeof( info ) / sizeof( DWORD ),
            ( ULONG_PTR* )&info );
        }
        __except ( EXCEPTION_CONTINUE_EXECUTION )
        {
        }
      }
    
      // TODO: check if ever inline
      LONG SyncInterlockedIncrement ( LONG *Dest )
      {
        return InterlockedIncrement ( Dest );
      }
    
      LONG SyncInterlockedExchangeAdd ( LONG *Dest, LONG Val )
      {
        return InterlockedExchangeAdd ( Dest, Val );
      }
    
      LONG SyncInterlockedExchange ( LONG *Dest, LONG Val )
      {
        return InterlockedExchange ( Dest, Val );
      }
    
    #else // !WIN32, so must be POSIX threads
    
      pthread_key_t threadname_key;
    
      CriticalSection::CriticalSection ( int spincount_unused )
      {
        pthread_mutex_init ( &mutex, NULL );
      }
    
      CriticalSection::~CriticalSection ( )
      {
        pthread_mutex_destroy ( &mutex );
      }
    
      void CriticalSection::Enter ( )
      {
        int ret = pthread_mutex_lock ( &mutex );
        if ( ret )
          ERROR_LOG ( COMMON, "%s: pthread_mutex_lock(%p) failed: %s
    ",
          __FUNCTION__, &mutex, strerror( ret ) );
      }
    
      bool CriticalSection::TryEnter ( )
      {
        return ( !pthread_mutex_trylock( &mutex ) );
      }
    
      void CriticalSection::Leave ( )
      {
        int ret = pthread_mutex_unlock ( &mutex );
        if ( ret )
          ERROR_LOG ( COMMON, "%s: pthread_mutex_unlock(%p) failed: %s
    ",
          __FUNCTION__, &mutex, strerror( ret ) );
      }
    
      Thread::Thread ( ThreadFunc function, void* arg ) : thread_id ( 0 )
      {
        pthread_attr_t attr;
        pthread_attr_init ( &attr );
        pthread_attr_setstacksize ( &attr, 1024 * 1024 );
        int ret = pthread_create ( &thread_id, &attr, function, arg );
        if ( ret )
          ERROR_LOG ( COMMON, "%s: pthread_create(%p, %p, %p, %p) failed: %s
    ",
          __FUNCTION__, &thread_id, &attr, function, arg, strerror( ret ) );
    
        INFO_LOG ( COMMON, "created new thread %lu (func=%p, arg=%p)
    ", thread_id,
          function, arg );
      }
    
      Thread::~Thread ( )
      {
        WaitForDeath ( );
      }
    
      void Thread::WaitForDeath ( )
      {
        if ( thread_id )
        {
          void* exit_status;
          int ret = pthread_join ( thread_id, &exit_status );
          if ( ret )
            ERROR_LOG ( COMMON, "error joining thread %lu: %s
    ", thread_id,
            strerror( ret ) );
          if ( exit_status )
            ERROR_LOG ( COMMON, "thread %lu exited with status %d
    ", thread_id,
            *( int * )exit_status );
          thread_id = 0;
        }
      }
    
      void Thread::SetAffinity ( int mask )
      {
        // This is non-standard
    #ifdef __linux__
        cpu_set_t cpu_set;
        CPU_ZERO ( &cpu_set );
    
        for ( unsigned int i = 0; i < sizeof( mask ) * 8; i++ )
        {
          if ( ( mask >> i ) & 1 )
          {
            CPU_SET ( i, &cpu_set );
          }
        }
    
        pthread_setaffinity_np ( thread_id, sizeof( cpu_set ), &cpu_set );
    #endif
      }
    
      void Thread::SetCurrentThreadAffinity ( int mask )
      {
    #ifdef __linux__
        cpu_set_t cpu_set;
        CPU_ZERO ( &cpu_set );
    
        for ( size_t i = 0; i < sizeof( mask ) * 8; i++ )
        {
          if ( ( mask >> i ) & 1 )
          {
            CPU_SET ( i, &cpu_set );
          }
        }
    
        pthread_setaffinity_np ( pthread_self( ), sizeof( cpu_set ), &cpu_set );
    #endif
      }
    
      void InitThreading ( )
      {
        static int thread_init_done = 0;
        if ( thread_init_done )
          return;
    
        if ( pthread_key_create( &threadname_key, NULL /* free */ ) != 0 )
          perror ( "Unable to create thread name key: " );
    
        thread_init_done++;
      }
    
      void SleepCurrentThread ( int ms )
      {
        usleep ( 1000 * ms );
      }
    
      void SetCurrentThreadName ( const TCHAR* szThreadName )
      {
        pthread_setspecific ( threadname_key, strdup( szThreadName ) );
        INFO_LOG ( COMMON, "%s(%s)
    ", __FUNCTION__, szThreadName );
      }
    
      Event::Event ( )
      {
        is_set_ = false;
      }
    
      void Event::Init ( )
      {
        pthread_cond_init ( &event_, 0 );
        pthread_mutex_init ( &mutex_, 0 );
      }
    
      void Event::Shutdown ( )
      {
        pthread_mutex_destroy ( &mutex_ );
        pthread_cond_destroy ( &event_ );
      }
    
      void Event::Set ( )
      {
        pthread_mutex_lock ( &mutex_ );
    
        if ( !is_set_ )
        {
          is_set_ = true;
          pthread_cond_signal ( &event_ );
        }
    
        pthread_mutex_unlock ( &mutex_ );
      }
    
      void Event::Wait ( )
      {
        pthread_mutex_lock ( &mutex_ );
    
        while ( !is_set_ )
        {
          pthread_cond_wait ( &event_, &mutex_ );
        }
    
        is_set_ = false;
        pthread_mutex_unlock ( &mutex_ );
      }
    
      LONG SyncInterlockedIncrement ( LONG *Dest )
      {
    #if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
        return __sync_add_and_fetch ( Dest, 1 );
    #else
        register int result;
        __asm__ __volatile__ ( "lock; xadd %0,%1" : "=r"( result ), "=m"( *Dest )
          : "0"( 1 ), "m"( *Dest ) : "memory" );
        return result;
    #endif
      }
    
      LONG SyncInterlockedExchangeAdd ( LONG *Dest, LONG Val )
      {
    #if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
        return __sync_add_and_fetch ( Dest, Val );
    #else
        register int result;
        __asm__ __volatile__ ( "lock; xadd %0,%1" : "=r"( result ), "=m"( *Dest )
          : "0"( Val ), "m"( *Dest ) : "memory" );
        return result;
    #endif
      }
    
      LONG SyncInterlockedExchange ( LONG *Dest, LONG Val )
      {
    #if defined(__GNUC__) && defined (__GNUC_MINOR__) && ((4 < __GNUC__) || (4 == __GNUC__ && 1 <= __GNUC_MINOR__))
        return __sync_lock_test_and_set ( Dest, Val );
    #else
        register int result;
        __asm__ __volatile__ ( "lock; xchg %0,%1" : "=r"( result ), "=m"( *Dest )
          : "0"( Val ), "m"( *Dest ) : "memory" );
        return result;
    #endif
      }
    
    #endif
    
    } // namespace Common
  • 相关阅读:
    获取aspx页面执行时间完全解决方案
    WebForm中DataGrid的20篇经典文章
    不走寻常路 设计ASP.NET应用程序的七大绝招
    动态绑定dropdownlist 开始拣.NET
    Notes中几个处理多值域的通用函数
    Lotus开发之Lotus Notes中域的验证
    Undokumentierte @Formeln/LotusScript im Lotus Notes Client/Server
    domino server端的Notes.ini详解
    Lotus开发基本性能优化
    以Ajax方式显示Lotus Notes视图的javasript类库NotesView2
  • 原文地址:https://www.cnblogs.com/shangdawei/p/4042108.html
Copyright © 2020-2023  润新知