天天看點

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 線程,這與它是誰的成員變量并無關系。