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

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

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

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

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

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

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

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

 

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

线程函数:

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一类函数,而必须使用上述的方案。

 

 

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:[email protected] - 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; // // Cant 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; // // Cant 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\n" );
    }
    else
    {
      // lpParam points to the argument; in this case it is an int

      // DEBUG_LOG(CONSOLE, "Timer[%i] will call back\n", *(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\n", 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)\n",
        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)\n",
        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)\n",
        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\n",
      __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\n",
      __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\n",
      __FUNCTION__, &thread_id, &attr, function, arg, strerror( ret ) );

    INFO_LOG ( COMMON, "created new thread %lu (func=%p, arg=%p)\n", 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\n", thread_id,
        strerror( ret ) );
      if ( exit_status )
        ERROR_LOG ( COMMON, "thread %lu exited with status %d\n", 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)\n", __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

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。