临界区对象

Critical Section Objects

A critical section object provides synchronization similar to that provided by a mutex object, except that a critical section can be used only by the threads of a single process. Event, mutex, and semaphore objects can also be used in a single-process application, but critical section objects provide a slightly faster, more efficient mechanism for mutual-exclusion synchronization (a processor-specific test and set instruction). Like a mutex object, a critical section object can be owned by only one thread at a time, which makes it useful for protecting a shared resource from simultaneous access. Unlike a mutex object, there is no way to tell whether a critical section has been abandoned.

Starting with Windows Server 2003 SP1, threads waiting on a critical section do not acquire the critical section on a first-come, first-serve basis. This change increases performance significantly for most code. However, some applications depend on FIFO ordering and may perform poorly or not at all on current versions of Windows (for example, applications that have been using critical sections as a rate-limiter). To ensure that your code continues to work correctly, you may need to add an additional level of synchronization. For example, suppose you have a producer thread and a consumer thread that are using a critical section object to synchronize their work. Create two event objects, one for each thread to use to signal that it is ready for the other thread to proceed. The consumer thread will wait for the producer to signal its event before entering the critical section, and the producer thread will wait for the consumer thread to signal its event before entering the critical section. After each thread leaves the critical section, it signals its event to release the other thread.

临界区对象提供类似于互斥器对象的同步,但只能由单个进程的线程使用。事件、互斥器和信号量对象也可以在单进程应用程序中使用,但临界区提供了一种更快,更有效的互斥同步机制。像互斥器对象一样,一个临界区对象只能一次由一个线程拥有,这对于保护共享资源免于同时访问非常有用。与互斥器对象不同,无法判断临界区是否已近被放弃。

从Windows Server 2003 SP1开始,等待临界区的线程不会以先到先得的方式获取临界区。此更改可显着提高大多数代码的性能。但是,某些应用程序依赖于FIFO排序,并且在当前版本的Windows上可能表现不佳或根本不表现(例如,已将关键部分用作速率限制器的应用程序)。为确保代码继续正常工作,您可能需要添加其他级别的同步。例如,假设您有一个生产者线程和一个使用关键部分对象来同步其工作的消费者线程。创建两个事件对象,每个对象用于表示已准备好让另一个线程继续运行的每个线程。消费者线程将在进入临界区之前等待生产者发出其事件的信号,并且生产者线程将在进入临界区之前等待消费者线程发出其事件的信号。每个线程离开临界区后,它会发出事件信号以释放另一个线程。

Windows Server 2003和Windows XP / 2000 / NT:正在等待临界区的线程被添加到等待队列中;它们被唤醒并且通常按照它们被添加到队列中的顺序获取临界区。但是,如果以足够快的速率将线程添加到此队列,则由于唤醒每个等待线程所花费的时间,性能可能会降低。

临界区对象的封装:

//头文件

class CLock
{
public:
CLock();
~CLock();

void Lock();
BOOL TryLock(BOOL bTry = TRUE);
void Unlock();
private:
CRITICAL_SECTION m_csObject;
};

//实现文件

CLock::CLock()
{
::InitializeCriticalSection(&m_csObject);
}

CLock::~CLock()
{
::DeleteCriticalSection(&m_csObject);
}

void CLock::Lock()
{
::EnterCriticalSection(&m_csObject);
}

void CLock::Unlock()
{
::LeaveCriticalSection(&m_csObject);
}

BOOL CLock::TryLock(BOOL bTry/* = TRUE*/)
{
BOOL bRet = ::TryEnterCriticalSection(&m_csObject);
if (bRet && bTry)
{
::LeaveCriticalSection(&m_csObject);
}
return bRet;
}

另外设计一个CScopeLock类,方便使用:

template<typename T>
class CScopeLock
{
public:
CScopeLock(T& obj)
:m_obj(obj)
{
m_obj.Lock();
}
~CScopeLock()
{
m_obj.Unlock();
}

private:
T& m_obj;
};

猜你喜欢

转载自www.cnblogs.com/sooksjb/p/9282621.html