【Poco笔记】线程Thread
简单介绍
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;
};