POCO C++解析之一 一般线程
来源:互联网 发布:蓝牙单片机程序 编辑:程序博客网 时间:2024/06/03 13:33
这一部分主要包括了Thread、ThreadImpl类,封装了线程操作并提供了命名线程功能。
一、基本概况
隶属模块: Foundation
Thread是线程接口类,其主要功能是由ThreadImpl来实现的。根据不同的平台,实现相应平台的线程操作。
class Thread : private ThreadImpl{ // …};因为Thread的主要功能实现来自于ThreadImpl,因此Thread内部的功能函数大部分都是类似于下面的风格:
void Thread::start(Runnable& target){ startImpl(target);}
即将Thread类成员的调用传递给ThreadImpl类相应功能的成员。这样的好处是在其接口不变的情况下实现可以随意变化。这里的变化主要来自于不同的平台。
这个封装最核心的部分应该是start()函数了,此函数用来启动一个线程。Thread类使用重载的方法定义了两个start()函数。
void startImpl(Runnable& target);void startImpl(Callable target, void* pData = 0);void Thread::start(Runnable& target){ startImpl(target);}
二、 Thread和ThreadImpl类的数据成员
Thread
// 线程ID,不是pthread_t类型,只是作为Thread线程唯一标识。
int _id;
// 线程名称。
std::string _name;
// 此对象为每个线程管理一些数据
ThreadLocalStorage* _pTLS;
// 实现线程互斥锁
mutable FastMutex _mutex;
ThreadImpl
// 用来存储线程数据
AutoPtr<ThreadData> _pData;
// 静态变量,用来存储当前线程对象。
static CurrentThreadHolder _currentThreadHolder;
为了了解上面出现的相关类变量类型的实现,这里也将代码贴上看着方便:
下面两个类是作为ThreadImpl的内部类定义的。
class CurrentThreadHolder{public: CurrentThreadHolder() { if (pthread_key_create(&_key, NULL)) throw SystemException("cannot allocate thread context key"); } ~CurrentThreadHolder() { pthread_key_delete(_key); } ThreadImpl* get() const { return reinterpret_cast<ThreadImpl*>(pthread_getspecific(_key)); } void set(ThreadImpl* pThread) { pthread_setspecific(_key, pThread); }private: pthread_key_t _key;};struct ThreadData: public RefCountedObject{ ThreadData(): pRunnableTarget(0), pCallbackTarget(0), thread(0), prio(PRIO_NORMAL_IMPL), osPrio(0), done(false), stackSize(POCO_THREAD_STACK_SIZE) {#if defined(POCO_VXWORKS) // This workaround is for VxWorks 5.x where // pthread_init() won't properly initialize the thread. std::memset(&thread, 0, sizeof(thread));#endif } Runnable* pRunnableTarget; AutoPtr<CallbackData> pCallbackTarget; pthread_t thread; int prio; int osPrio; Event done; std::size_t stackSize;};
二、 线程主要实现
这个start()函数的实现导致直接调用ThreadImpl::startImpl()函数。这里根据不同平台提供了不同的实现,这里主要是针对UNIX的实现进行分析。
void ThreadImpl::startImpl(Runnable& target){// 首先判断当前的线程是否存在,如果存在pRunnableTarget就不可能为空。(下面有赋值操作)if (_pData->pRunnableTarget)throw SystemException("thread already running");// 定义并初始化线程属性pthread_attr_t attributes;pthread_attr_init(&attributes);// 设置线程栈的大小if (_pData->stackSize != 0){if (0 != pthread_attr_setstacksize(&attributes, _pData->stackSize))throw SystemException("cannot set thread stack size");}// 这里是设置运行接口。(见下说明(1))_pData->pRunnableTarget = ⌖// 创建一个线程,线程主函数为runnableEntry, 参数为当前线程对象。// (见下说明(2))if (pthread_create(&_pData->thread, &attributes, runnableEntry, this)){_pData->pRunnableTarget = 0;throw SystemException("cannot start thread");}// 设置线程优先级if (_pData->prio != PRIO_NORMAL_IMPL){struct sched_param par;par.sched_priority = mapPrio(_pData->prio);if (pthread_setschedparam(_pData->thread, SCHED_OTHER, &par))throw SystemException("cannot set thread priority");}}
(1)、线程接口是POCO C++提供的一个需要实现的抽象类。
class Foundation_API Runnable{public: Runnable();virtual ~Runnable();virtual void run() = 0;};
用户自定义类主要是实现其run()函数。上面程序中函数接口应该是用户已经实现了的一个Runnable对象。
(2)、当创建一个线程以后,执行流就会进入runnableEntry函数。
void* ThreadImpl::runnableEntry(void* pThread){// 首先将当前的线程对象存储到静态变量中。这里的pThread就是上面调用的this指针。_currentThreadHolder.set(reinterpret_cast<ThreadImpl*>(pThread));// 设置忽略的信号集#if defined(POCO_OS_FAMILY_UNIX)sigset_t sset;sigemptyset(&sset);sigaddset(&sset, SIGQUIT);sigaddset(&sset, SIGTERM);sigaddset(&sset, SIGPIPE); pthread_sigmask(SIG_BLOCK, &sset, 0);#endif// 将pThread还原为最初的线程对象。ThreadImpl* pThreadImpl = reinterpret_cast<ThreadImpl*>(pThread);// 获取线程数据AutoPtr<ThreadData> pData = pThreadImpl->_pData;try{// 通过接口回调的方式调用线程接口run()pData->pRunnableTarget->run();}catch (Exception& exc){ErrorHandler::handle(exc);}catch (std::exception& exc){ErrorHandler::handle(exc);}catch (...){ErrorHandler::handle();}// 清空线程对象。pData->pRunnableTarget = 0;// 这里的done是线程条件变量实现的,set函数是通知其他线程。pData->done.set();return 0;}
这里看到线程最终实现是一个无参的函数Runnable::run(),用户要做的只是实现一个Runnable对象即可。
如果线程的执行需要提供参数怎么办呢?ThreadImpl提供了另外一个start()函数。
注意:这里的参数不是Runnable,而是Callable类型对象和一个void指针。
void ThreadImpl::startImpl(Callable target, void* pData){// 首先判断当前线程是否正在执行。if (_pData->pCallbackTarget && _pData->pCallbackTarget->callback)throw SystemException("thread already running");// 定义并初始化线程属性pthread_attr_t attributes;pthread_attr_init(&attributes);// 设置线程栈if (_pData->stackSize != 0){if (0 != pthread_attr_setstacksize(&attributes, _pData->stackSize))throw SystemException("can not set thread stack size");}// 获取/创建线程回调对象 (见下说明 (1) )if (0 == _pData->pCallbackTarget.get())_pData->pCallbackTarget = new CallbackData;// 设置回调对象的回调函数和参数_pData->pCallbackTarget->callback = target;_pData->pCallbackTarget->pData = pData;// 创建线程 (callableEntry实现见下(1))if (pthread_create(&_pData->thread, &attributes, callableEntry, this)){_pData->pCallbackTarget->callback = 0;_pData->pCallbackTarget->pData = 0;throw SystemException("cannot start thread");}// 设置优先级if (_pData->prio != PRIO_NORMAL_IMPL){struct sched_param par;par.sched_priority = mapPrio(_pData->prio);if (pthread_setschedparam(_pData->thread, SCHED_OTHER, &par))throw SystemException("cannot set thread priority");}}
(1)、callableEntry实现
void* ThreadImpl::callableEntry(void* pThread){_currentThreadHolder.set(reinterpret_cast<ThreadImpl*>(pThread));#if defined(POCO_OS_FAMILY_UNIX)sigset_t sset;sigemptyset(&sset);sigaddset(&sset, SIGQUIT);sigaddset(&sset, SIGTERM);sigaddset(&sset, SIGPIPE); pthread_sigmask(SIG_BLOCK, &sset, 0);#endifThreadImpl* pThreadImpl = reinterpret_cast<ThreadImpl*>(pThread);AutoPtr<ThreadData> pData = pThreadImpl->_pData;try{// 与runnableEntry最大的不同在这里,这里以带有一个参数的函数作为线程的主操作。pData->pCallbackTarget->callback(pData->pCallbackTarget->pData);}catch (Exception& exc){ErrorHandler::handle(exc);}catch (std::exception& exc){ErrorHandler::handle(exc);}catch (...){ErrorHandler::handle();}pData->pCallbackTarget->callback = 0;pData->pCallbackTarget->pData = 0;pData->done.set();return 0;}
(2)、线程回调对象见上(一)。
Callable类型是 函数指针
typedef void (*Callable)(void*);
用户只要将一个此类型的函数传递进来就可以。
startImpl()函数调用pData->pCallbackTarget->callback(pData->pCallbackTarget->pData);来执行线程。
另外,线程类的封装还有很多线程相关的功能。如setPriority()等,这些功能实现比较简单,这里主要是解释了线程类的主要实现部分。
- POCO C++解析之一 一般线程
- Poco 线程
- 【C解析之一】数据类型
- POCO线程池
- Poco线程池
- poco线程池设计
- POCO线程池分析
- POCO线程类分析
- Poco::TCPServer框架解析
- Poco::TCPServer框架解析
- Poco::TCPServer框架解析
- Poco::TCPServer框架解析
- Poco 线程、任务实现: Poco Task 、Poco Thread
- C语言深度解析之一
- Poco c ++ 库安装
- c++Poco库
- Poco解析XML小例子
- Android 中的线程及 AsyncTask(线程形态之一)解析一下
- 记毕业季——唯有努力才能前行
- 【评论】阿里云os,到底是不是android OS
- IOS学习之UINavigationController详解与使用(二)页面切换和segmentedController
- 条款39:明智而审慎的使用private继承
- JSF Newbie - Error message - Property X not found on type November 6, 2011 - 14:25 rss181919 Offline
- POCO C++解析之一 一般线程
- IOS学习之UINavigationController详解与使用(三)ToolBar
- vs2008 配置 wxWidgets-2.9.4
- zend studio 9.0.3 破解与汉化
- HDU 2574 素数因子数目
- 2012 ACM/ICPC Asia Regional Chengdu Online-hdu 4288
- 解题报告-HDOJ-1232(并查集)
- validation
- Android Gallery实现滑动翻页效果