Test the efficiency of the exclusion objects in Windows

来源:互联网 发布:阿里云企业邮箱mx验证 编辑:程序博客网 时间:2024/05/06 19:29

There are mainly four kinds of exclusion objects, which can be used in solving the problems of race condition, on Windows platform. They are Critical Section, Mutex, Semaphore, and Event. As most people know, Critical Section is the fastest way to achieve mutual exclusion, while the other three have the same efficiency more or less. The reason is that Critical Section is not a kernel object. It is only a local object within some process. Using it will not cause the switch of the executing mode from user mode to kernel mode. So it saves a lot of time. But the biggest weakness followed is that Critical Section can only be used in a single process, i.e., any of the threads in that same process can access it, while other threads or processes cannot.

The following code tests the efficiency of the four exclusion objects in Windows OS. The IDE is Visual Studio 2008 Team Suite, with DotNet Framework 3.5.

//Exclusion.h

#ifndef _EXCLUSION_H_
#define _EXCLUSION_H_

#include 
<windows.h>
#include 
<cassert>
#include 
<cstdlib>
#include 
<iostream>
using namespace std;

class Exclusion {
public:
    
virtual void Initialize() = 0;
    
virtual void Destroy() = 0;
    
virtual void Lock() = 0;
    
virtual void Unlock() = 0;
}
;

class CriticalSectionExclusion : public Exclusion {
private:
    CRITICAL_SECTION _cs;
public:
    CriticalSectionExclusion() 
{}
    
void Initialize() { InitializeCriticalSection(&_cs); }
    
void Destroy() { DeleteCriticalSection(&_cs); }
    
void Lock() { EnterCriticalSection(&_cs); }
    
void Unlock() { LeaveCriticalSection(&_cs); }
    
bool TryLock() return (TryEnterCriticalSection(&_cs) == TRUE) ? true : false; }
}
;

class MutexExclusion : public Exclusion {
private:
    HANDLE _mutex;
    LPCWSTR _name;
public:
    MutexExclusion() : _mutex(
0), _name(0{}
    MutexExclusion(LPCWSTR lpname) : _mutex(
0), _name(lpname) {}
    
void Initialize() { _mutex = CreateMutex(0, TRUE, _name); assert(_mutex != 0); }
    
void Destroy() { CloseHandle(_mutex); }
    
void Lock() if(WaitForSingleObject(_mutex, INFINITE) != WAIT_OBJECT_0) abort(); }
    
void Unlock() { ReleaseMutex(_mutex); }
}
;

class SemaphoreExclusion : public Exclusion {
private:
    HANDLE _semaphore;
    LPCWSTR _name;
public:
    SemaphoreExclusion() : _semaphore(
0), _name(0{}
    SemaphoreExclusion(LPCWSTR lpname) : _semaphore(
0), _name(lpname) {}
    
void Initialize() { _semaphore = CreateSemaphore(011, _name); assert(_semaphore != 0); }
    
void Destroy() { CloseHandle(_semaphore); }
    
void Lock() if(WaitForSingleObject(_semaphore, INFINITE) != WAIT_OBJECT_0) abort(); }
    
void Unlock() { ReleaseSemaphore(_semaphore, 10); }
}
;

class EventExclusion : public Exclusion {
private:
    HANDLE _event;
    LPCWSTR _name;
public:
    EventExclusion() : _event(
0), _name(0{}
    EventExclusion(LPCWSTR name) : _event(
0), _name(name) {}
    
void Initialize() { _event = CreateEvent(0, FALSE, TRUE, _name); assert(_event != 0); }
    
void Destroy() { CloseHandle(_event); }
    
void Lock() if(WaitForSingleObject(_event, INFINITE) != WAIT_OBJECT_0) abort(); }
    
void Unlock() { SetEvent(_event); }
}
;

#endif

//Time.h

#ifndef _TIME_H_
#define _TIME_H_

#include 
<windows.h>

class Time {
public:
    
virtual void Initialize() = 0;
    
virtual void Start() = 0;
    
virtual void Stop() = 0;
    
virtual double GetOnceTime() = 0;
    
virtual double GetTotalTime() = 0;
    
virtual void Reset() = 0;
}
;

class TickCountTime : public Time {

}
;

class QueryPerformanceTime : public Time {
private:
    LARGE_INTEGER _head;
    LARGE_INTEGER _tail;
    LARGE_INTEGER _freq;
    LONGLONG _once_time;
    LONGLONG _total_time;
public:
    
void Initialize() {
        _once_time 
= _total_time = 0;
        QueryPerformanceFrequency(
&_freq);
        memset(
&_head, 0sizeof(LARGE_INTEGER));
        memset(
&_head, 0sizeof(LARGE_INTEGER));
    }

    
void Start() { QueryPerformanceCounter(&_head); }
    
void Stop() {
        QueryPerformanceCounter(
&_tail);
        _once_time 
= _tail.QuadPart - _head.QuadPart;
        _total_time 
+= _once_time;
    }

    
double GetOnceTime() return ((double)_once_time) / _freq.QuadPart; }
    
double GetTotalTime() return ((double)_total_time) / _freq.QuadPart; }
    
void Reset() {
        _once_time 
= _total_time = 0;
        memset(
&_head, 0sizeof(LARGE_INTEGER));
        memset(
&_tail, 0sizeof(LARGE_INTEGER));
    }

}
;

class AssemblyInstructionTime : public Time {

}
;

#endif

//main.cpp

#include "Exclusion.h"
#include 
"Time.h"
#include 
<iostream>
#include 
<cstdio>
using namespace std;

int main() {
    Exclusion 
* my_ex;
    Time 
* my_tm = new QueryPerformanceTime();
    my_tm
->Initialize();
    
short flag;

    flag 
= 0;
    my_ex 
= new CriticalSectionExclusion();
    my_ex
->Initialize();
    my_tm
->Start();
    
while(++flag > 0{
        my_ex
->Lock();
        my_ex
->Unlock();
    }

    my_tm
->Stop();
    printf(
"CritialSection: %1.10lf s ", my_tm->GetTotalTime());

    flag 
= 0;
    my_tm
->Reset();
    my_ex 
= new MutexExclusion();
    my_ex
->Initialize();
    my_tm
->Start();
    
while(++flag > 0{
        my_ex
->Lock();
        my_ex
->Unlock();
    }

    my_tm
->Stop();
    printf(
"Mutex: %1.10lf s ", my_tm->GetTotalTime());

    flag 
= 0;
    my_tm
->Reset();
    my_ex 
= new SemaphoreExclusion();
    my_ex
->Initialize();
    my_tm
->Start();
    
while(++flag > 0{
        my_ex
->Lock();
        my_ex
->Unlock();
    }

    my_tm
->Stop();
    printf(
"Semaphore: %1.10lf s ", my_tm->GetTotalTime());

    flag 
= 0;
    my_tm
->Reset();
    my_ex 
= new EventExclusion();
    my_ex
->Initialize();
    my_tm
->Start();
    
while(++flag > 0{
        my_ex
->Lock();
        my_ex
->Unlock();
    }

    my_tm
->Stop();
    printf(
"Event: %1.10lf s ", my_tm->GetTotalTime());

    delete my_tm;
    
return 0;
}

The running result is shown below.

CriticalSection: 0.0050035730 s

Mutex:                 0.0473425394 s

Semaphore:      0.0465372747 s

Event:                  0.0444654282 s

The data indicates that if Critical Section is sufficient to be used in some case, never turn to the other three choices.