【Poco笔记】线程Thread

2019-03-01  本文已影响0人  安安爸Chris

简单介绍

Poco的Thread是对标准库std::thread的封装,同时它类似Java一样,提供了Runnable接口。所以使用上是对标Java的。
与标准库不同的是,Poco::Thread创建和运行时相分离的。这一点标准库设计确实不太友好。例如下面例子。

// 线程中运行的函数
void func() {
    std::cout<< "Hello World!"<<std::endl;
}

// 标准库创建时即运行
std::thread t(func);

使用Poco::Thread

同样看例子

void func(void* param) {
    const char* str = reinterpret_cast<const char*>(param);
    std::cout<< "Hello World! "<< str << std::endl;
}

class FuncRunnable : public Poco::Runnable{
    void run() override {
        std::cout<< "Hello World! I'm runnable!"<<std::endl;
    }
};

struct Functor {
    void operator()  () {
        std::cout<< "Hello World! I'm functor"<<std::endl;
    }
};

class ThreadDemo : public Poco::Util::ServerApplication {
public:
    int main(const std::vector<std::string>& args) override {
        FuncRunnable r;

        // way 1
        Poco::Thread thread1;
        thread1.start(r);

        // way 2
        Poco::Thread thread2;
        const char *test = "test";
        thread2.start(func, (void*)test);

        // way 3
        Poco::Thread thread3;
        thread3.startFunc(Functor());

        // way 4
        Poco::Thread thread4;
        thread4.startFunc([](){
            std::cout<< "Hello World! I'm lambda!"<<std::endl;
        });

        thread1.join();
        thread2.join();
        thread3.join();
        thread4.join();

        waitForTerminationRequest();
    };
};

POCO_SERVER_MAIN(ThreadDemo);

由上面可见,使用基本跟Java类似。创建与运行也分离了。


看一下主要的运行接口,摘自Poco1.9源码

    void start(Runnable& target);
        /// Starts the thread with the given target.
        ///
        /// Note that the given Runnable object must remain
        /// valid during the entire lifetime of the thread, as
        /// only a reference to it is stored internally.

    void start(Callable target, void* pData = 0);
        /// Starts the thread with the given target and parameter.

    template <class Functor>
    void startFunc(Functor fn)
        /// Starts the thread with the given functor object or lambda.
    {
        startImpl(new FunctorRunnable<Functor>(fn));
    }

1.9源码分析

源码文件主要包含
1.Thread.h/Thread.cpp
提供外部调用接口
在Thread.cpp中定义了两种Holder, RunnableHolder和CallableHolder。Holder技术是Poco框架中经常用到的,是对某一种类型对象的指针包装。
Runnable为线程运行类的基类,
Callable为带一个参数的方法

class RunnableHolder: public Runnable
{
public:
    RunnableHolder(Runnable& target):
        _target(target)
    {
    }

    ~RunnableHolder()
    {
    }

    void run()
    {
        _target.run();
    }

private:
    Runnable& _target;
};

class CallableHolder: public Runnable
{
public:
    CallableHolder(Thread::Callable callable, void* pData):
        _callable(callable),
        _pData(pData)
    {
    }

    ~CallableHolder()
    {
    }

    void run()
    {
        _callable(_pData);
    }

private:
    Thread::Callable _callable;
    void* _pData;
};

2.Thread_POSIX.h/Thread_POSIX.cpp
3.Thread_VX.h/Thread_VX.cpp
4.Thread_WIN32.h/Thread_WIN32.cpp
5.Thread_WINCE.h/Thread_WINCE.cpp
这几个文件,每个文件中都定义了ThreadImpl,用于不同平台下的具体实现,Thread私有继承ThreadImp,ThreadImp用于哪一个文件由编译宏决定。

顺便说一下POSIX系统下的实现。因为使用的是c++98,当时没有thread类,所以所有的实现都是使用pthread库来实现的。具体的使用请参考pthread技术文档。


6.ThreadLocal.h/ThreadLocal.cpp
ThreadLocal中定义了三个类, TLSAbstractSlot类, TLSSlot类, ThreadLocalStorage类


关系图

TLSAbstractSlot是基类,TLSSlot是模板类,通过模板技术包裹了具体的类型。ThreadLocalStorage是用于线程存储,具体是通过一个map来实现。
因为1.9使用的是c++98,还没有引用local_thread关键字,所以这里是通过这种方式实现。

ThreadLocalStorage定义如下

class Foundation_API ThreadLocalStorage
    /// This class manages the local storage for each thread.
    /// Never use this class directly, always use the
    /// ThreadLocal template for managing thread local storage.
{
public:
    ThreadLocalStorage();
    ~ThreadLocalStorage();

    TLSAbstractSlot*& get(const void* key);
        /// Returns the slot for the given key.
        
    static ThreadLocalStorage& current();
        /// Returns the TLS object for the current thread
        /// (which may also be the main thread).
        
    static void clear();
        /// Clears the current thread's TLS object.
        /// Does nothing in the main thread.
    
private:
    typedef std::map<const void*, TLSAbstractSlot*> TLSMap;
    
    TLSMap _map;

    friend class Thread; // Poco::Thread
};


// ********************************cpp 中实现****************************************
namespace
{
    static SingletonHolder<ThreadLocalStorage> sh; 
    // 单例模式,ThreadLocalStorage实际上是一个map,这里就是全局的一个map
}

// 如果可以获取到当前thread,则调用thread->tls
// 否则调用单例ThreadLocalStorage
ThreadLocalStorage& ThreadLocalStorage::current()
{
    Thread* pThread = Thread::current();
    if (pThread)
    {
        return pThread->tls();
    }
    else
    {
        return *sh.get();
    }
}

那么Poco::Thread的tls是如何定义的?

ThreadLocalStorage& Thread::tls()
{
    if (!_pTLS)
        _pTLS = new ThreadLocalStorage;
    return *_pTLS;
}

2.0源码分析

Poco还没有正式发布2.0,但是从开发版本来看,新版本的变动还是挺大的。主要是使用了c++11对框架的适配与优化

源码文件比较少,主要如下文件
1.Thread.h/Thread.cpp

2.Thread_STD.h/Thread_POSIX.cpp/Thread_VX.cpp/Thread_WIN32.cpp

Thread.h 主要对实现类ThreadImp的包装,并定义了对外接口。
Thread_STD.h定义了内部实现,主要提供了ThreadImp
Thread_POSIX.cpp/Thread_VX.cpp/Thread_WIN32.cpp分别定义不同平台下的兼容实现

在Thread_STD.h中定义了几个重要类型

// 线程中跑的函数签名
typedef void (*Callable)(void*);

在Thread.cpp中增加了两种

private修饰的ThreadData,定义了线程内部数据。 1.9中源码分别定义在各个平台实现类中,这里抽离出来定义在Thread.cpp中。较之前的定义,这里额外的是新增了std::thread指针。因为直接引用了c++11中的thread,有些实现直接借助于它。

struct ThreadData: public RefCountedObject
{
        ThreadData():
            thread(),
            prio(PRIO_NORMAL_IMPL),
            policy(0),
            task(0),
            done(Event::EVENT_MANUALRESET),
            stackSize(POCO_THREAD_STACK_SIZE),
            cpu(-1),
            started(false),
            joined(false)
                {  }

        SharedPtr<Runnable> pRunnableTarget; // 实现函数
        std::unique_ptr<std::thread>     thread;  // 底层实现依托于std::thread
        TIDImpl       tid; //底层id
        int           prio;  
        int           osPrio;
        int           policy;
        int           task;
        Event         done;
        std::size_t   stackSize;
        int           cpu;
        bool          started;
        bool          joined;
    };
上一篇下一篇

猜你喜欢

热点阅读