的代码项目文章。
基于瓦尔杜克的S代码,我重写了关键部分类,不同之处在于我的实现将递归(Reentrantable)锁定特性集成到一个关键部分类中(FYI,valdok提供了两个类:一个没有递归,另一个带有递归)。
我只想验证一下,我的实现仍然是正确和完整的。
的所有版本提供try_enter()功能。
#pragma once
#include <windows.h>
#include <intrin.h>
#pragma intrinsic(_WriteBarrier)
#pragma intrinsic(_ReadWriteBarrier)
class critical_section
{
private:
struct cpu_type
{
enum type
{
unknown,
single,
multiple
};
};
public:
critical_section(u32 spin_count=0)
: m_semaphore(null)
, m_thread_id(0)
, m_wait_count(0)
, m_spin_count(0)
, m_recur_count(0)
{
// determine the cpu type
if( m_cpu_type == cpu_type::unknown )
{
SYSTEM_INFO sys_info;
::GetSystemInfo(&sys_info);
m_cpu_type = (sys_info.dwNumberOfProcessors > 1)?cpu_type::multiple:cpu_type::single;
}
// set the spin count.
set_spin_count(spin_count);
}
~critical_section()
{
if(m_semaphore != null)
{
CloseHandle(m_semaphore);
m_semaphore = null;
}
::memset(this, 0, sizeof(*this));
}
void set_spin_count(u32 count)
{
// on single core, there should be no spinning at all.
if(m_cpu_type == cpu_type::multiple)
{
m_spin_count = count;
}
}
public:
bool enter(u32 timeout=INFINITE)
{
u32 cur_thread_id = ::GetCurrentThreadId();
if(cur_thread_id == m_thread_id)
{
// already owned by the current thread.
m_recur_count++;
}
else
{
if((!m_thread_id && lock_immediate(cur_thread_id))
|| (timeout && lock_internal(cur_thread_id, timeout)))
{
// successfully locked!
m_recur_count = 1;
}
else
{
// failed to lock!
return false;
}
}
return true;
}
bool try_enter()
{
return enter(0);
}
void leave()
{
assert(m_recur_count > 0);
if(--m_recur_count == 0)
{
unlock_internal();
}
}
inline bool is_acquired() const
{
return (::GetCurrentThreadId() == m_thread_id);
}
private:
inline bool lock_immediate(u32 thread_id)
{
// return true only if m_thread_id was 0 (and, at the same time, replaced by thread_id).
return (_InterlockedCompareExchange(reinterpret_cast<long volatile*>(&m_thread_id), thread_id, 0) == 0);
}
bool lock_kernel(u32 thread_id, u32 timeout)
{
bool waiter = false;
for(u32 ticks=GetTickCount();;)
{
if(!waiter) _InterlockedIncrement(reinterpret_cast<long volatile*>(&m_wait_count));
// try locking once again before going to kernel-mode.
if(lock_immediate(thread_id)) return true;
u32 wait;
if(timeout==INFINITE)
{
wait = INFINITE;
}
else
{
// update the remaining time-out.
wait = GetTickCount()-ticks;
if(timeout<=wait) return false; // timed-out
wait = timeout-wait;
}
// go kernel
assert(m_semaphore!=null);
switch(WaitForSingleObject(m_semaphore, wait))
{
case WAIT_OBJECT_0:
// got a change!
waiter = false;
break;
case WAIT_TIMEOUT:
// timed-out.
// but, there's one more change in the upper section of the loop.
waiter = true;
break;
default:
assert(false);
}
}
}
bool lock_internal(u32 thread_id, u32 timeout)
{
// try spinning and locking
for(u32 spin=0; spin<m_spin_count; spin++)
{
if(lock_immediate(thread_id)) return true;
// give chance to other waiting threads.
// on single-core, it does nothing.
YieldProcessor();
}
// prepare semaphore object for kernel-mode waiting.
allocate_semaphore();
bool locked = lock_kernel(thread_id, timeout);
_InterlockedDecrement(reinterpret_cast<long volatile*>(&m_wait_count));
return locked;
}
void unlock_internal()
{
// changes done to the shared resource are committed.
_WriteBarrier();
// reset owner thread id.
m_thread_id = 0;
// critical section is now released.
_ReadWriteBarrier();
// if there are waiting threads:
if(m_wait_count > 0)
{
_InterlockedDecrement(reinterpret_cast<long volatile*>(&m_wait_count));
// wake up one of them by incrementing semaphore count by 1.
assert(m_semaphore);
ReleaseSemaphore(m_semaphore, 1, null);
}
}
void allocate_semaphore()
{
if(m_semaphore==null)
{
// create a semaphore object.
HANDLE semaphore = CreateSemaphore(null, 0, 0x7FFFFFFF, null);
assert(semaphore!=null);
// try assign it to m_semaphore.
if(InterlockedCompareExchangePointer(&m_semaphore, semaphore, null)!=null)
{
// other thread already created and assigned the semaphore.
CloseHandle(semaphore);
}
}
}
private:
// prevent copying
critical_section(const critical_section&);
void operator=(const critical_section&);
private:
// type of cpu: single-core or multiple-core
static cpu_type::type m_cpu_type;
// owner thread's id
volatile u32 m_thread_id;
// number of waiting threads
volatile u32 m_wait_count;
// spinning count
volatile u32 m_spin_count;
// recursion(reentrance) count
s32 m_recur_count;
// semaphore for kernel-mode wait
volatile HANDLE m_semaphore;
};不要担心静态成员。critical_section::m_cpu_type在其他.cpp文件中被定义并初始化为unknown。
发布于 2012-05-30 10:51:35
老实说,很难通过干运行代码来验证这类工作。
我会采用原始代码,并设计一些测试用例,显示它的工作。使用和不使用代码运行它们。
然后设计一些测试用例,这些测试用例由于您发现的问题而失败,或者在没有增强的情况下工作得不够好。
在新代码上运行这些测试用例(所有这些测试用例不仅仅是最新的测试用例),并且您知道您的代码是否有效。
https://codereview.stackexchange.com/questions/1836
复制相似问题