天天看点

OpenThreads库介绍——Block

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 ;
}
           

运行程序的结果:

OpenThreads库介绍——Block

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