美文网首页
【Poco笔记】线程Thread

【Poco笔记】线程Thread

作者: 安安爸Chris | 来源:发表于2019-03-01 22:24 被阅读0次

    简单介绍

    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用于哪一个文件由编译宏决定。

    • POCO_OS_FAMILY_WINDOWS
      定义了WINDOWS平台
    • _WIN32_WCE
      定义了WINDOWS CE
    • POCO_VXWORKS
      定义了VXWORKS平台
      注:VXWORKS是美国 Wind River System 公司推出的操作系统

    顺便说一下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;
        };
    

    相关文章

      网友评论

          本文标题:【Poco笔记】线程Thread

          本文链接:https://www.haomeiwen.com/subject/bjsilqtx.html