0

我写了一个递归锁,它的行为喜欢临界区。但是当我实现递归功能时我遇到了问题。像这样的代码:

#include "own_cs.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <assert.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdio.h>


struct own_critical_section
{
    long   own_lock_count;          // count of locked thread, -1 means unlock , other means lock.
    HANDLE own_event;               // auto-reset
    DWORD  own_owning_thread_id;    // owner thread of lock
};


void InitialOwnCriticalSection( own_critical_section** own_cs)
{
    *own_cs = (own_critical_section*)malloc( sizeof( own_critical_section ) );
    (*own_cs)->own_lock_count = -1;
    (*own_cs)->own_event = CreateEventW( NULL, FALSE, FALSE, NULL );
    (*own_cs)->own_owning_thread_id = 0;
}

void DeleteOwnCriticalSection( own_critical_section* own_cs )
{
    assert( own_cs != NULL );

    CloseHandle( own_cs->own_event );
    free( own_cs );
}

void EnterOwnCriticalSection( own_critical_section* own_cs )
{
    for ( int spin_count = 0; spin_count < 500; ++ spin_count )
    {//spinlock
        if ( -1L == InterlockedCompareExchange( &own_cs->own_lock_count, -1L, -1L ) )
            break;
        Sleep(0);
    }

    if( 0 < InterlockedIncrement( &own_cs->own_lock_count ) &&
        ( own_cs->own_owning_thread_id != ::GetCurrentThreadId() ) ) 
//there is no guarantee that own_owning_thread_id is set before comparison with tid.so this comparison is not thread-safe.
    {   
        //locked
        WaitForSingleObject( own_cs->own_event, INFINITE ); 
    }

    own_cs->own_owning_thread_id = ::GetCurrentThreadId();
}

void LeaveOwnCriticalSection( own_critical_section* own_cs )
{
    if( -1L != InterlockedDecrement( &own_cs->own_lock_count ) &&
        (::GetCurrentThreadId() == own_cs->own_owning_thread_id ) )
    {
        SetEvent( own_cs->own_event );
    }
}

问题是 EnterOwnCriticalSection 例程;作为该函数中的注释,不保证在与 tid 比较之前设置 own_owning_thread_id。所以这种比较不是线程安全的。

4

1 回答 1

1
#include "own_cs.h"  
#define WIN32_LEAN_AND_MEAN  
#include <windows.h>  
#include <assert.h>  
#include <malloc.h>  
#include <stdlib.h>  
#include <stdio.h>  


struct own_critical_section  
{  
    long   own_lock_count;          // count of locked thread, -1 means unlock , other means lock.  
    HANDLE own_event;               // auto-reset  
    DWORD  own_owning_thread_id;    // owner thread of lock  
    long   own_recursion_count;     // count of recursion  
};  


void InitialOwnCriticalSection( own_critical_section** own_cs)  
{  
    *own_cs = (own_critical_section*)malloc( sizeof( own_critical_section ) );  
    (*own_cs)->own_lock_count = -1;  
    (*own_cs)->own_event = CreateEventW( NULL, FALSE, FALSE, NULL );  
    (*own_cs)->own_owning_thread_id = 0;  
    (*own_cs)->own_recursion_count = 0;  
}  

void DeleteOwnCriticalSection( own_critical_section* own_cs )  
{  
    assert( own_cs != NULL );  

    CloseHandle( own_cs->own_event );  
    free( own_cs );  
}  

void EnterOwnCriticalSection( own_critical_section* own_cs )  
{  
    assert( own_cs->own_lock_count>=-1L );  

    DWORD current_thread_id = GetCurrentThreadId();  

    if ( own_cs->own_owning_thread_id != current_thread_id )  
    {  
        for ( int spin_count = 0; spin_count < 500; ++ spin_count )  
        {//spinlock  
            if ( -1L == InterlockedCompareExchange( &own_cs->own_lock_count, -1L, -1L ) )  
                break;  
            Sleep(0);  
        }     
    }  

    // if current thread is the acquired thread,   
    // own_cs->own_owning_thread_id = current_thread_id  
    // else if current thread is not the acquired thread  
    // own_cs->own_owning_thread_id should be 0 or the thread_id which is acquired thread.  
    if( 0 < InterlockedIncrement( &own_cs->own_lock_count ) &&  
        ( own_cs->own_owning_thread_id != current_thread_id ) )  
    {     
        //locked  
        WaitForSingleObject( own_cs->own_event, INFINITE );    
    }  

    // inside lock  
    ++own_cs->own_recursion_count;  
    own_cs->own_owning_thread_id = current_thread_id;  
}  

void LeaveOwnCriticalSection( own_critical_section* own_cs )  
{  
    assert( own_cs->own_lock_count>=-1L && own_cs->own_recursion_count>=0 );  

    if ( --own_cs->own_recursion_count == 0 )  
        own_cs->own_owning_thread_id = 0;  

    if( -1L != InterlockedDecrement( &own_cs->own_lock_count ) &&  
        ( 0 == own_cs->own_recursion_count ) )  
    {  
        SetEvent( own_cs->own_event );  
    }  
}  

上面的代码已更新。我添加评论指出。

于 2012-07-02T06:42:21.223 回答