POCO库 Foundation::Thread模块 多线程与线程池支持

    本节主要介绍Thread类和ThreadLocal机制的使用方法以及实现原理,以及对ThreadPool线程池支持的简单了解


   Thread类使用方法

        在C++语言中,我们通过_beginThreadex或CreateThread来创建线程(最好使用前者,关于两者区别和线程基础知识可参见《Windows核心编程》),并且提供一个原型为void MyFunc(void pParam)入口函数来完成任务。在Poco中,将入口函数抽象为一个类Runnable,该类提供void run()接口,用户需要继承至该类来实现自定义的入口函数。Poco将线程也抽象为一个类Thread,提供了start, join等方法。一个Thread使用例子如下:

#include "Poco/Thread.h"
#include "Poco/Runnable.h"
#include <iostream>
class HelloRunnable: public Poco::Runnable
{
    virtual void run()
    {
        std::cout << "Hello, world!" << std::endl;
    }
};
int main(int argc, char** argv)
{
    HelloRunnable runnable;
    Poco::Thread thread;
    thread.start(runnable);//传入对象而不是对象指针
    thread.join();
    return 0;
}

    定义一个Thread对象,调用其start方法并传入一个Runnable对象来启动线程,使用的方法比较简单,另外,如果你的线程的入口函数在另一个已定义好的类中,那么Poco提供了一个适配器来使线程能够从你指定的入口启动,并且无需修改已有的类:

#include "Poco/Thread.h"
#include "Poco/RunnableAdapter.h"
#include <iostream>
class Greeter
{
public:
    void greet()
   {
       std::cout << "Hello, world!" << std::endl;
   }
};
int main(int argc, char** argv)
{
    Greeter greeter;
    Poco::RunnableAdapter<Greeter> runnable(greeter, &Greeter::greet);
    Poco::Thread thread;
    thread.start(runnable);
    thread.join();//等待该线程技术
    return 0;
}

看完了其使用方法之后,我们来查看其内部实现。


   Thread和Runnable如何工作

先看看thread.start是怎么启动一个新线程的:

在Poco-1.4.6/Foundation/src/Thread_WIN32中找到start的实现startImpl:

void ThreadImpl::startImpl(Runnable& target)
{
	if (isRunningImpl())
		throw SystemException("thread already running");

	_pRunnableTarget = ⌖ //记录入口

	createImpl(runnableEntry, this);
}

    该函数先判断线程是否正在运行,然后将Runnable对象指针存入成员_pRunnableTarget中,之后调用createImpl函数,并传入runnableEntry函数地址和this指针

void ThreadImpl::createImpl(Entry ent, void* pData)
{
#if defined(_DLL)
	_thread = CreateThread(NULL, _stackSize, ent, pData, 0, &_threadId);
#else
	unsigned threadId;
	_thread = (HANDLE) _beginthreadex(NULL, _stackSize, ent, this, 0, &threadId);
	_threadId = static_cast<DWORD>(threadId);
#endif
	if (!_thread)
		throw SystemException("cannot create thread");
	if (_prio != PRIO_NORMAL_IMPL && !SetThreadPriority(_thread, _prio))
		throw SystemException("cannot set thread priority");
}


    其中Entry ent参数也就是runnableEntry函数代码如下:

#if defined(_DLL)
DWORD WINAPI ThreadImpl::runnableEntry(LPVOID pThread)
#else
unsigned __stdcall ThreadImpl::runnableEntry(void* pThread)
#endif
{
	_currentThreadHolder.set(reinterpret_cast<ThreadImpl*>(pThread));
#if defined(_DEBUG) && defined(POCO_WIN32_DEBUGGER_THREAD_NAMES)
	setThreadName(-1, reinterpret_cast<Thread*>(pThread)->getName().c_str());
#endif
	try
	{
		reinterpret_cast<ThreadImpl*>(pThread)->_pRunnableTarget->run();
	}
	catch (Exception& exc)
	{
		ErrorHandler::handle(exc);
	}
	catch (std::exception& exc)
	{
		ErrorHandler::handle(exc);
	}
	catch (...)
	{
		ErrorHandler::handle();
	}
	return 0;
}


    可以看出,createImpl负责创建线程,并且把入口函数runnableEntry作为线程入口,将this指针作为参数。在runnableEntry中,首先将pThread也就是代表该线程的Threal对象地址放入_currentThreadHolder中,static CurrentThreadHolder _currentThreadHolder;是一个静态数据成员,它的存在是为了方便程序在任何环境下通过Thread::current来获取当前运行线程所属的Thread对象指针。CurrentThreadHolder是ThreadImpl的一个内嵌类,它通过线程的TLS机制将线程的Thread指针放入TLS数组的某个槽中(_slot),并提供存取(set)和获取(get)方法,源码如下:

class CurrentThreadHolder
{
	public:
		CurrentThreadHolder(): _slot(TlsAlloc())
		{
			if (_slot == TLS_OUT_OF_INDEXES)
				throw SystemException("cannot allocate thread context key");
		}
		~CurrentThreadHolder()
		{
			TlsFree(_slot);
		}
		ThreadImpl* get() const
		{
			return reinterpret_cast<ThreadImpl*>(TlsGetValue(_slot));
		}
		void set(ThreadImpl* pThread)
		{
			TlsSetValue(_slot, pThread);
		}
	
	private:
		DWORD _slot;
};


runnableEntry在通过_currentThreadHolder存取了Thread指针之后,便开始调用用户在Runnable类中定义的run函数。

ThreadImpl类还提供了一系列线程相关的方法:

void ThreadImpl::joinImpl()
{
	if (!_thread) return;

	switch (WaitForSingleObject(_thread, INFINITE))
	{
	case WAIT_OBJECT_0:
		threadCleanup();
		return;
	default:
		throw SystemException("cannot join thread");
	}
}


bool ThreadImpl::joinImpl(long milliseconds)
{
	if (!_thread) return true;

	switch (WaitForSingleObject(_thread, milliseconds + 1))
	{
	case WAIT_TIMEOUT:
		return false;
	case WAIT_OBJECT_0:
		threadCleanup();
		return true;
	default:
		throw SystemException("cannot join thread");
	}
}


bool ThreadImpl::isRunningImpl() const
{
	if (_thread)
	{
		DWORD ec = 0;
		return GetExitCodeThread(_thread, &ec) && ec == STILL_ACTIVE;
	}
	return false;
}


void ThreadImpl::threadCleanup()
{
	if (!_thread) return;
	if (CloseHandle(_thread)) _thread = 0;
}


ThreadImpl* ThreadImpl::currentImpl()
{
	return _currentThreadHolder.get();
}


ThreadImpl::TIDImpl ThreadImpl::currentTidImpl()
{
    return GetCurrentThreadId();
}



  RunnableAdapter适配器:

      下面我们再看看RunnableAdapter是如何运用适配器模式的,在Poco-1.4.6/Foundation/Include/RunnableAdaper.h中找到RunnableAdaper类的实现:

template <class C>
class RunnableAdapter: public Runnable
	/// This adapter simplifies using ordinary methods as
	/// targets for threads.
	/// U
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值