对互斥体 信号量 事件和临界区的一些小看法

上面转了一篇说明
互斥体  信号量 事件和临界区的文章
写的还可以,从使用的角度去分析
其实临界区并不是内核态的对象

所以也就不难理解为什么临界区不能跨进程使用

可以看一下临界区的定义

typedef struct _RTL_CRITICAL_SECTION {
    PRTL_CRITICAL_SECTION_DEBUG DebugInfo;

    //
    //  The following three fields control entering and exiting the critical
    //  section for the resource
    //

    LONG LockCount;
    LONG RecursionCount;
    HANDLE OwningThread;        // from the thread's ClientId->UniqueThread
    HANDLE LockSemaphore;
    ULONG_PTR SpinCount;        // force size on 64-bit systems when packed
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;

主要是通过 LockCount RecursionCount 和OwningThread来控制
相当于一个引用计数,如果不为空,这个进程就要等待,如果为空了,就可以进入.
因为不涉及到内核态对象,所以临界区的操作跟互斥体不是一个量级
参考网上有人做的测试,效率差20倍左右.
而对于event 和 mutex
先看两者定义

typedef struct _KEVENT {
    DISPATCHER_HEADER Header;
} KEVENT, *PKEVENT, *PRKEVENT;

typedef struct _KMUTANT {
    DISPATCHER_HEADER Header;
    LIST_ENTRY MutantListEntry;
    struct _KTHREAD *OwnerThread;
    BOOLEAN Abandoned;
    UCHAR ApcDisable;
} KMUTANT, *PKMUTANT, *PRKMUTANT, KMUTEX, *PKMUTEX, *PRKMUTEX;

mutex 是event的超集

mutex比event多了一个ownerthread,当调用releasemutex时,如果mutex的ownerthread不是你调用的线程,会失败

而event不存在此问题

mutext更多的是用在对同一个资源访问互斥上,

而event更多用于线程同步,

另外event可以设置是否是手动设置恢复信号,这个mutex是做不到的,也就是说如果event是手动的,setevent可以令等待它的N个线程激活

但是mutext只能同一时刻允许一个线程获得使用权.不可能用mutex做到,让等待它的多个线程同时解锁.

如果只有两个线程的话,我觉得两者的差别就没有那么大了.

贴上msdn的两个例子就可以更清楚的看到两者之间的差别

第二个例子中的mutex完全可以用event代替.

#include 
#include 

#define THREADCOUNT 4 

HANDLE ghGlobalWriteEvent; 
HANDLE ghReadEvents[THREADCOUNT];

DWORD WINAPI ThreadProc(LPVOID);

void CreateEventsAndThreads(void) 
{
    HANDLE hThread; 
    DWORD i, dwThreadID; 

    // Create a manual-reset event object. The master thread sets 
    // this to nonsignaled when it writes to the shared buffer. 

    ghGlobalWriteEvent = CreateEvent( 
        NULL,               // default security attributes
        TRUE,               // manual-reset event
        TRUE,               // initial state is signaled
        TEXT("WriteEvent")  // object name
        ); 

    if (ghGlobalWriteEvent == NULL) 
    { 
        printf("CreateEvent failed (%d)\n", GetLastError());
        return;
    }
    else if ( GetLastError() == ERROR_ALREADY_EXISTS )
    {
        printf("Named event already exists.\n");
        return;
    }

    // Create multiple threads and an auto-reset event object 
    // for each thread. Each thread sets its event object to 
    // signaled when it is not reading from the shared buffer. 

    for(i = 0; i < THREADCOUNT; i++) 
    {
        // Create the auto-reset event
        ghReadEvents[i] = CreateEvent( 
            NULL,     // no security attributes
            FALSE,    // auto-reset event
            TRUE,     // initial state is signaled
            NULL);    // object not named

        if (ghReadEvents[i] == NULL) 
        {
            printf("CreateEvent failed (%d)\n", GetLastError());
            return;
        }

        hThread = CreateThread(NULL, 
            0, 
            ThreadProc, 
            &ghReadEvents[i],  // pass event handle
            0, 
            &dwThreadID); 

        if (hThread == NULL) 
        {
            printf("CreateThread failed (%d)\n", GetLastError());
            return;
        }
    }
}

void WriteToBuffer(VOID) 
{
    DWORD dwWaitResult, i; 

    // Reset ghGlobalWriteEvent to nonsignaled, to block readers
 
    if (! ResetEvent(ghGlobalWriteEvent) ) 
    { 
        printf("ResetEvent failed (%d)\n", GetLastError());
        return;
    } 

    // Wait for all reading threads to finish reading

    dwWaitResult = WaitForMultipleObjects( 
        THREADCOUNT,   // number of handles in array
        ghReadEvents,  // array of read-event handles
        TRUE,          // wait until all are signaled
        INFINITE);     // indefinite wait

    switch (dwWaitResult) 
    {
        // All read-event objects were signaled
        case WAIT_OBJECT_0: 
            // TODO: Write to the shared buffer
            printf("Main thread writing to the shared buffer...\n");
            break;

        // An error occurred
        default: 
            printf("Wait error: %d\n", GetLastError()); 
            ExitProcess(0); 
    } 

    // Set ghGlobalWriteEvent to signaled

    if (! SetEvent(ghGlobalWriteEvent) ) 
    {
        printf("SetEvent failed (%d)\n", GetLastError());
        ExitProcess(0);
    }

    // Set all read events to signaled
    for(i = 0; i < THREADCOUNT; i++) 
        if (! SetEvent(ghReadEvents[i]) ) 
        { 
            printf("SetEvent failed (%d)\n", GetLastError());
            return;
        } 
}

void CloseEvents()
{
    int i;

    for( i=0; i < THREADCOUNT; i++ )
        CloseHandle(ghReadEvents[i]);

    CloseHandle(ghGlobalWriteEvent);
}

void main()
{
    int i;

    // TODO: Create the shared buffer

    // Create the events and THREADCOUNT threads to read from the buffer

    CreateEventsAndThreads();

    // Write to the buffer three times, just for test purposes

    for(i=0; i < 3; i++)
        WriteToBuffer();

    // Close the events

    CloseEvents();
}

DWORD WINAPI ThreadProc(LPVOID lpParam) 
{
    DWORD dwWaitResult;
    HANDLE hEvents[2]; 

    hEvents[0] = *(HANDLE*)lpParam;  // thread's read event
    hEvents[1] = ghGlobalWriteEvent; // global write event

    dwWaitResult = WaitForMultipleObjects( 
        2,            // number of handles in array
        hEvents,      // array of event handles
        TRUE,         // wait till all are signaled
        INFINITE);    // indefinite wait

    switch (dwWaitResult) 
    {
        // Both event objects were signaled
        case WAIT_OBJECT_0: 
            // TODO: Read from the shared buffer
            printf("Thread %d reading from buffer...\n", 
                   GetCurrentThreadId());
            break; 

        // An error occurred
        default: 
            printf("Wait error: %d\n", GetLastError()); 
            ExitThread(0); 
    }

    // Set the read event to signaled

    if (! SetEvent(hEvents[0]) ) 
    { 
        printf("SetEvent failed (%d)\n", GetLastError());
        ExitThread(0);
    } 

    return 1;
}
这个是event的

#include 
#include 

#define THREADCOUNT 2

HANDLE ghMutex; 

DWORD WINAPI WriteToDatabase( LPVOID );

void main()
{
    HANDLE aThread[THREADCOUNT];
    DWORD ThreadID;
    int i;

    // Create a mutex with no initial owner

    ghMutex = CreateMutex( 
        NULL,              // default security attributes
        FALSE,             // initially not owned
        NULL);             // unnamed mutex

    if (ghMutex == NULL) 
    {
        printf("CreateMutex error: %d\n", GetLastError());
        return;
    }

    // Create worker threads

    for( i=0; i < THREADCOUNT; i++ )
    {
        aThread[i] = CreateThread( 
                     NULL,       // default security attributes
                     0,          // default stack size
                     (LPTHREAD_START_ROUTINE) WriteToDatabase, 
                     NULL,       // no thread function arguments
                     0,          // default creation flags
                     &ThreadID); // receive thread identifier

        if( aThread[i] == NULL )
        {
            printf("CreateThread error: %d\n", GetLastError());
            return;
        }
    }

    // Wait for all threads to terminate

    WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);

    // Close thread and mutex handles

    for( i=0; i < THREADCOUNT; i++ )
        CloseHandle(aThread[i]);

    CloseHandle(ghMutex);
}

DWORD WINAPI WriteToDatabase( LPVOID lpParam )
{ 
    DWORD dwCount=0, dwWaitResult; 

    // Request ownership of mutex.

    while( dwCount < 20 )
    { 
        dwWaitResult = WaitForSingleObject( 
            ghMutex,    // handle to mutex
            INFINITE);  // no time-out interval
 
        switch (dwWaitResult) 
        {
            // The thread got ownership of the mutex
            case WAIT_OBJECT_0: 
                __try { 
                    // TODO: Write to the database
                    printf("Thread %d writing to database...\n", 
                           GetCurrentThreadId());
                    dwCount++;
                } 

                __finally { 
                    // Release ownership of the mutex object
                    if (! ReleaseMutex(ghMutex)) 
                    { 
                        // Deal with error.
                    } 
                } 
                break; 

            // The thread got ownership of an abandoned mutex
            case WAIT_ABANDONED: 
                return FALSE; 
        }
    }
    return TRUE; 
}


这个是mutex的


你可能感兴趣的:(对互斥体 信号量 事件和临界区的一些小看法)