1. 简介
Block 是OpenThreads中的阻塞器类。顾名思义,这个类的作用就是阻塞线程的执行,使用block()阻塞执行它的线程(注意,不一定是定义它的Thread 线程,而是当前执行了block 函数的线程,包括系统主进程),并使用release()释放之前被阻塞的线程。
2. 实现
OpenThreads库中的Block文件中包括两个类的实现:Block和BlockCount,后者添加了一个计数器,控制多次操作之后释放阻塞的线程。 它与阻塞器类的使用方法基本相同:block()阻塞线程,release()释放线程;不过除此之外,BlockCount 的构造函数还可以设置一个阻塞计数值。计数的作用是:每当阻塞器对象的completed()函数被执行一次,计数器就减一,直至减到零
就释放被阻塞的线程。
2.1 Block
Block类是使用OpenThreads中的Condition来实现的,在传统的线程概念(比如C++11中)并没有一个与之对应的类,Block的成员中包括
Mutex mut;
Condition cond;
bool released;
在Block的Block方法实现如下:
inline bool block()
{
ScopedLock<OpenThreads::Mutex> mutlock(mut);
if( !released )
{
return cond.wait(&mut)==;
}
else
{
return true;
}
}
可以看到它是通过一个Condition来阻塞运行这个函数的线程,并等待其他线程唤醒这个运行它的线程。唤醒的操作在release函数中实现:
inline void release()
{
ScopedLock<OpenThreads::Mutex> mutlock(_mut);
if (!_released)
{
_released = true;
_cond.broadcast();
}
}
这里使用的是Condition中的broadcast方法(没有使用signal),也就是同时释放多个阻塞的线程。
由此可以知道这个类的使用方式:在A线程中调用它的block方法,导致A线程被阻塞。然后在B线程中调用它的release方法,释放被阻塞的A线程。(也可以在多个线程中调用block方法,导致多个线程被阻塞,然后B线程可以调用release方法一次性释放多个被阻塞的线程)
2.2 BlockCount
它的block和release实现和Block完全几乎一样,但是它里面有一个计数器,实现如下:
inline void block()
{
OpenThreads::ScopedLock<OpenThreads::Mutex> mutlock(_mut);
if (_currentCount)
_cond.wait(&_mut);
}
如果_currentCount是0,那么不会进入阻塞。
inline void release()
{
OpenThreads::ScopedLock<OpenThreads::Mutex> mutlock(_mut);
if (_currentCount)
{
_currentCount = ;
_cond.broadcast();
}
}
在realse中同样是会根据_currentCount值来释放所有的线程。假设想使用一个BlockCount来实现和Block一样的功能,那么必须这样做:
//首先声明一个BlockCount
BlockCount bc;
//设置它的Count不是0,设置任何非零的正整数都可以
bc.setBlockCount();
//然后就可以和Block一样在一个线程中调用阻塞它
bc.block();
//另一个线程中唤醒
bc.release();
除此之外,这个类提供了一个completed的函数,用来递减技术,当计数为0,释放被阻塞的线程
inline void completed()
{
OpenThreads::ScopedLock<OpenThreads::Mutex> mutlock(_mut);
if (_currentCount>)
{
--_currentCount;
if (_currentCount==)
{
// osg::notify(osg::NOTICE)<<"Released"<<std::endl;
_cond.broadcast();
}
}
}
也就是这个类可以让释放被阻塞线程的那个线程(上文示例中的B线程)可以有一个计数器,通过这个计数器到0,决定释放所有其他线程。
3. 示例
#include <OpenThreads/Thread>
#include <OpenThreads/Condition>
#include <OpenThreads/Mutex>
#include <OpenThreads/ScopedLock>
#include <OpenThreads/Block>
#include <iostream>
class TestThread : public OpenThreads::Thread
{
public:
TestThread() : _done(false), _count(){ }
~TestThread() { cancel(); }
void block(){ _block.block(); }
virtual int cancel()
{
_block.release();
_done = true;
while (isRunning())
{
OpenThreads::Thread::YieldCurrentThread();
}
return ;
}
virtual void run()
{
do
{
std::cout << "(" << _count << ")";
++_count;
if (_count == )
{
_block.release();
_block.reset();
_block.block();
}
microSleep();
} while (!_done);
}
protected:
bool _done;
unsigned long _count;
OpenThreads::Block _block;
};
int main()
{
TestThread t;
t.start();
t.block();
std::cout << "(Main)" << std::endl;
getchar();
t.cancel();
return ;
}
运行程序的结果:

可以发现,Block::block()函数将首先阻塞主进程,被释放后再次阻塞的是TestThread 线程,这与它是谁的成员变量并无关系。