C++ 中的 CountDownLatch使用 Boost 互斥体和条件
我尝试使用 boost 互斥体和条件变量来实现 CountDownLatch。下面是代码,我想知道是否需要添加其他内容。
我怎样才能对这段代码进行单元测试?
template< class TypeVal >
class AtomicCounter
{
public:
AtomicCounter( TypeVal val ) : m_typeVal( val )
{
}
AtomicCounter() : m_typeVal(0)
{
}
AtomicCounter(const AtomicCounter& cpy) : m_typeVal(cpy.m_typeVal)
{
boost::mutex::scoped_lock scoped_lock(cpy.m_atomicMutex);
m_typeVal = cpy.m_typeVal;
}
const AtomicCounter& operator=(const AtomicCounter& other)
{
if (this == &other)
return *this;
boost::mutex::scoped_lock lock1(&m_atomicMutex < &other.m_atomicMutex ? m_atomicMutex : other.m_atomicMutex);
boost::mutex::scoped_lock lock2(&m_atomicMutex > &other.m_atomicMutex ? m_atomicMutex : other.m_atomicMutex);
m_typeVal = other.m_typeVal;
return *this;
}
virtual ~AtomicCounter()
{
}
const TypeVal& getCount() const
{
boost::mutex::scoped_lock lock( m_atomicMutex );
return m_typeVal;
}
const TypeVal& setCount( const TypeVal &val )
{
boost::mutex::scoped_lock lock( m_atomicMutex );
m_typeVal = val;
return m_typeVal;
}
const TypeVal& increment()
{
boost::mutex::scoped_lock lock( m_atomicMutex );
m_typeVal++ ;
return m_typeVal;
}
const TypeVal& decrement()
{
boost::mutex::scoped_lock lock( m_atomicMutex );
m_typeVal-- ;
return m_typeVal;
}
const TypeVal& increment(const TypeVal& t)
{
boost::mutex::scoped_lock lock( m_atomicMutex );
m_typeVal+=t ;
return m_typeVal;
}
const TypeVal& decrement(const TypeVal& t)
{
boost::mutex::scoped_lock lock( m_atomicMutex );
m_typeVal-=t ;
return m_typeVal;
}
private:
mutable boost::mutex m_atomicMutex;
TypeVal m_typeVal;
};
class CountDownLatch
{
public:
CountDownLatch( int count ): m_cdlCount( count )
{
}
CountDownLatch(const CountDownLatch& cpy)
{
boost::unique_lock<boost::mutex>::unique_lock(const_cast<boost::mutex&>(cpy.m_cdlMutex));
m_cdlCount = cpy.m_cdlCount;
}
const CountDownLatch& operator=(const CountDownLatch& other)
{
if (this == &other)
return *this;
boost::mutex::scoped_lock lock1(const_cast<boost::mutex&>(&m_cdlMutex < &other.m_cdlMutex ? m_cdlMutex : other.m_cdlMutex));
boost::mutex::scoped_lock lock2(const_cast<boost::mutex&>(&m_cdlMutex > &other.m_cdlMutex ? m_cdlMutex : other.m_cdlMutex));
m_cdlCount = other.m_cdlCount;
return *this;
}
virtual ~CountDownLatch()
{
}
void wait()
{
boost::mutex::scoped_lock lock( m_cdlMutex );
if( m_cdlCount.getCount() > 0 )
{
m_cdlCondition.wait( lock );
}
}
void wait( uint64_t timeoutMicros )
{
boost::mutex::scoped_lock lock( m_cdlMutex );
if( m_cdlCount.getCount() > 0 )
{
boost::posix_time::time_duration td = boost::posix_time::milliseconds( timeoutMicros );
m_cdlCondition.timed_wait( lock, td );
}
}
void countDown()
{
boost::mutex::scoped_lock lock( m_cdlMutex );
if( m_cdlCount.decrement() == 0 )
{
m_cdlCondition.notify_all();
}
}
int getCount()
{
return m_cdlCount.getCount();
}
private:
boost::mutex m_cdlMutex;
boost::condition_variable m_cdlCondition;
AtomicCounter< int > m_cdlCount;
};
I tried to implement CountDownLatch using boost mutexes and condition variable. Below is the code and would like to know if I need to add anything else.
How can I unit test this code as well?
template< class TypeVal >
class AtomicCounter
{
public:
AtomicCounter( TypeVal val ) : m_typeVal( val )
{
}
AtomicCounter() : m_typeVal(0)
{
}
AtomicCounter(const AtomicCounter& cpy) : m_typeVal(cpy.m_typeVal)
{
boost::mutex::scoped_lock scoped_lock(cpy.m_atomicMutex);
m_typeVal = cpy.m_typeVal;
}
const AtomicCounter& operator=(const AtomicCounter& other)
{
if (this == &other)
return *this;
boost::mutex::scoped_lock lock1(&m_atomicMutex < &other.m_atomicMutex ? m_atomicMutex : other.m_atomicMutex);
boost::mutex::scoped_lock lock2(&m_atomicMutex > &other.m_atomicMutex ? m_atomicMutex : other.m_atomicMutex);
m_typeVal = other.m_typeVal;
return *this;
}
virtual ~AtomicCounter()
{
}
const TypeVal& getCount() const
{
boost::mutex::scoped_lock lock( m_atomicMutex );
return m_typeVal;
}
const TypeVal& setCount( const TypeVal &val )
{
boost::mutex::scoped_lock lock( m_atomicMutex );
m_typeVal = val;
return m_typeVal;
}
const TypeVal& increment()
{
boost::mutex::scoped_lock lock( m_atomicMutex );
m_typeVal++ ;
return m_typeVal;
}
const TypeVal& decrement()
{
boost::mutex::scoped_lock lock( m_atomicMutex );
m_typeVal-- ;
return m_typeVal;
}
const TypeVal& increment(const TypeVal& t)
{
boost::mutex::scoped_lock lock( m_atomicMutex );
m_typeVal+=t ;
return m_typeVal;
}
const TypeVal& decrement(const TypeVal& t)
{
boost::mutex::scoped_lock lock( m_atomicMutex );
m_typeVal-=t ;
return m_typeVal;
}
private:
mutable boost::mutex m_atomicMutex;
TypeVal m_typeVal;
};
class CountDownLatch
{
public:
CountDownLatch( int count ): m_cdlCount( count )
{
}
CountDownLatch(const CountDownLatch& cpy)
{
boost::unique_lock<boost::mutex>::unique_lock(const_cast<boost::mutex&>(cpy.m_cdlMutex));
m_cdlCount = cpy.m_cdlCount;
}
const CountDownLatch& operator=(const CountDownLatch& other)
{
if (this == &other)
return *this;
boost::mutex::scoped_lock lock1(const_cast<boost::mutex&>(&m_cdlMutex < &other.m_cdlMutex ? m_cdlMutex : other.m_cdlMutex));
boost::mutex::scoped_lock lock2(const_cast<boost::mutex&>(&m_cdlMutex > &other.m_cdlMutex ? m_cdlMutex : other.m_cdlMutex));
m_cdlCount = other.m_cdlCount;
return *this;
}
virtual ~CountDownLatch()
{
}
void wait()
{
boost::mutex::scoped_lock lock( m_cdlMutex );
if( m_cdlCount.getCount() > 0 )
{
m_cdlCondition.wait( lock );
}
}
void wait( uint64_t timeoutMicros )
{
boost::mutex::scoped_lock lock( m_cdlMutex );
if( m_cdlCount.getCount() > 0 )
{
boost::posix_time::time_duration td = boost::posix_time::milliseconds( timeoutMicros );
m_cdlCondition.timed_wait( lock, td );
}
}
void countDown()
{
boost::mutex::scoped_lock lock( m_cdlMutex );
if( m_cdlCount.decrement() == 0 )
{
m_cdlCondition.notify_all();
}
}
int getCount()
{
return m_cdlCount.getCount();
}
private:
boost::mutex m_cdlMutex;
boost::condition_variable m_cdlCondition;
AtomicCounter< int > m_cdlCount;
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
对于单元测试,您可以尝试压力测试。例如,对于 CountDownLatch,创建 25 个同时调用
CountDownLatch::countDown()
的测试线程、同时调用CountDownLatch::getCount()
的其他 25 个线程以及其他 25 个线程调用CountDownLatch::wait()
的线程。为了使事情更加同步,请使用屏障,或者让线程休眠直到相同的绝对时间。通过连接所有线程,确保所有线程正确终止(无死锁)。确保CountDownLatch::m_cdlCount
最终为零。多次运行相同的测试(在合理的时间内)。
您可以对 AtomicCounter 使用相同的基本思想。
可能还有其他技术来测试多线程代码,但这是我最熟悉的一种。
For unit testing, you can try stress-testing. For example, for CountDownLatch, create 25 test threads that simultaneously call
CountDownLatch::countDown()
, 25 other threads that simultaneously callCountDownLatch::getCount()
, and 25 others threads that callCountDownLatch::wait()
. To make things more simultaneous, use a barrier, or make the threads sleep until the same absolute time. Make sure that all threads terminate properly (no deadlocks) by joining all of them. Make sure thatCountDownLatch::m_cdlCount
ends up at zero.Run the same test many times (for a reasonable amount of time).
You can use the same basic idea for AtomicCounter.
There are probably other techniques for testing multitheaded code, but this is the one I'm most familiar with.