POCO C++库学习和分析 -- 线程 (一)

POCO C++库学习和分析 --  线程 (一)

 

         线程是程序设计中用的非常多的技术,在UI设计,网络通讯设计中广泛使用。在POCO库中,线程模块可以分成6个部分去理解。锁(Lock),线程(Thread),主动对象(ActiveObject),线程池(ThreadPool), 定时器(Timer)。下面对它们分别介绍。

 

1.  数据保护-锁

        线程是并行计算中比较复杂的技术之一,使用线程去设计问题时,在获取并行的好处时,也产生了racecondition的问题。锁的存在就是为了解决该问题。

POCO库封装了常见的几种锁,Mutex,Semaphore,Event,Scopelock,ReadWriteLock。类图分别如下:

        Mutex


        Semaphore


        Event


        ReadWriteLock

         类图非常的简单。就不再多说了,有兴趣的朋友可以自己去看。对于不同平台, POCO基本上选择了比较好的实现方式。比如在Mutex的实现时,Window上用的是criticalsection而非mutex。


2.  线程

        POCO对不同操作系统的线程进行了分装,使其变成了一个对象。下面是其的类图:


         熟悉JAVA的朋友一定会很开心,这不就是JAVA中使用线程的两种形式之一吗。所有的业务逻辑全部在Runnable中。Thread类只负责开始(Start)和停止(Join)两个动作。

         来看一下Thread的实现,在C++中底层API (windows下 _beginthreadex, linux下pthread_create)创建线程时必须要求入口函数是个全局或者静态函数,这要求业务具有唯一性。而事实上不同的线程就是为了完成不同业务的,不同对象对应不同线程。那变化时如何被封装至Thread类中呢。答案在下面。


[cpp]  view plain copy
  1. void ThreadImpl::createImpl(Entry ent, void* pData)  
  2. {  
  3. #if defined(_DLL)  
  4.     _thread = CreateThread(NULL, _stackSize, ent, pData, 0, &_threadId);  
  5. #else  
  6.     unsigned threadId;  
  7.     _thread = (HANDLE) _beginthreadex(NULL, _stackSize, ent, this, 0, &threadId);  
  8.     _threadId = static_cast<DWORD>(threadId);  
  9. #endif  
  10.     if (!_thread)  
  11.         throw SystemException("cannot create thread");  
  12.     if (_prio != PRIO_NORMAL_IMPL && !SetThreadPriority(_thread, _prio))  
  13.         throw SystemException("cannot set thread priority");  
  14. }  
  15.   
  16. #if defined(_DLL)  
  17. DWORD WINAPI ThreadImpl::callableEntry(LPVOID pThread)  
  18. #else  
  19. unsigned __stdcall ThreadImpl::callableEntry(void* pThread)  
  20. #endif  
  21. {  
  22.     _currentThreadHolder.set(reinterpret_cast<ThreadImpl*>(pThread));  
  23. #if defined(_DEBUG) && defined(POCO_WIN32_DEBUGGER_THREAD_NAMES)  
  24.     setThreadName(-1, reinterpret_cast<Thread*>(pThread)->getName().c_str());  
  25. #endif  
  26.     try  
  27.     {  
  28.         ThreadImpl* pTI = reinterpret_cast<ThreadImpl*>(pThread);  
  29.         pTI->_callbackTarget.callback(pTI->_callbackTarget.pData);  
  30.     }  
  31.     catch (Exception& exc)  
  32.     {  
  33.         ErrorHandler::handle(exc);  
  34.     }  
  35.     catch (std::exception& exc)  
  36.     {  
  37.         ErrorHandler::handle(exc);  
  38.     }  
  39.     catch (...)  
  40.     {  
  41.         ErrorHandler::handle();  
  42.     }  
  43.     return 0;  
  44. }  

在ThreadImpl::createImpl(Entry ent, void* pData)函数中创建线程时beginthreadex带入了this指针,也就是线程对象本身。

[cpp]  view plain copy
  1. _thread = (HANDLE) _beginthreadex(NULL, _stackSize, ent, this, 0, &threadId);  

线程对象本身存在一个结构体CallbackData,其中callback指向了真实的业务路口。不同线程对象在初始化时,会被赋值不同的业务入口函数。

而在静态函数callableEntry中,通过调用this指针可以运行真正的业务函数。

[cpp]  view plain copy
  1. ThreadImpl* pTI = reinterpret_cast<ThreadImpl*>(pThread);  
  2. pTI->_callbackTarget.callback(pTI->_callbackTarget.pData);  

最后用一段代码实例来结束吧
[cpp]  view plain copy
  1. #include "Poco/Thread.h"  
  2. #include "Poco/Runnable.h"  
  3. #include <iostream>  
  4. class HelloRunnable: public Poco::Runnable  
  5. {  
  6.        virtual void run()  
  7.        {  
  8.             std::cout << "Hello, world!" << std::endl;  
  9.        }  
  10. };  
  11. int main(int argc, char** argv)  
  12. {  
  13.        HelloRunnable runnable;  
  14.        Poco::Thread thread;  
  15.        thread.start(runnable);  
  16.        thread.join();  
  17.        return 0;  
  18. }  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值