原文地址:
http://yuyunwu.blog.sohu.com/82143947.html
完成线程类接口代码
上一篇文章中我们详细介绍了线程类的具体实现。本篇文章完成线程类接口类的代码。
一、使用条件编译预处理指令控制跨平台代码
因为我们的类库文件都是头文件的形式,所以它们总是以源代码形式和用户文件一起被编译,这样我们可以很方便地使用编译预处理在类库文件中控制跨平台代码。
大体上,平台控制代码具有下面的形式:
#if defined(LINUX)
#include <ThreadImpl_LINUX.h>
#elif defined(WIN32)
#include <ThreadImpl_WIN32.h>
#else
#error "Not supported OS type"
#endif // #if defined(LINUX)
另外需要说明的是,我们希望尽量把这种跨平台控制代码限制在类库层次,也就是说不希望它们出现在用户的源代码中,这样从根本上保证了用户代码的平台无关性。
二、将线程的例程函数定义为类静态成员函数
首先我们不能使用非静态成员函数作为线程的例程,因为这种成员函数被编译后产生的目标代码都会自动含有一个this指针,这与线程的例程函数的定义规格不符;我们可以使用全局函数或者局部函数(C++风格的局部函数是使用无名的命名空间---Unnamed namespaces限制函数,C风格的局部函数是使用static关键字),也可以使用类的静态函数。我们使用类静态函数,以增加它与线程类的关联性:
static int Thread_Function(Thread * pThread);
三、在析构函数中检测线程泄漏
我们在线程类的析构函数中检测线程的泄漏。具体说明请参考前面的文章。
四、完整的代码
(考虑到语言通用性,使用英语的注释)
//---- Thread.h ----
#ifndef THREAD_H
#define THREAD_H
#if defined(LINUX)
#include <ThreadImpl_LINUX.h>
#elif defined(WIN32)
#include <ThreadImpl_WIN32.h>
#else
#error "Not supported OS type"
#endif // #if defined(LINUX)
#include <string>
#include <Exception.h>
using std::string;
/**
*
*/
class ThreadException : public Exception {
public:
ThreadException(const string & strMsg = "")
: Exception(strMsg) {
}
};
/**
*
*/
class ThreadCreateException : public Exception {
public:
ThreadCreateException(const string & strMsg = "")
: Exception(strMsg) {
}
};
class ThreadImpl;
/**
* This class provides the methods on threads operations. Because
* most of thread modeles are firmly OS-dependent, so the class just
* provides a basic "synchronized thread model", and omits many
* other characteristics related to some specific OSes, if there
* is any.
*/
class Thread
{
public:
static const int WAIT_INFINITE = ThreadImpl::WAIT_INFINITE;
static const int INVALID_THREAD_ID = ThreadImpl::INVALID_THREAD_ID;
static const size_t DEFAULT_STACK_SIZE = ThreadImpl::DEFAULT_STACK_SIZE;
protected:
/**
* Internal thread information structure.
*/
ThreadImpl::ThreadStruct m_ts;
/**
* The name of the thread, or "" for unnamed.
*/
string m_strThreadName;
public:
/**
* Construction method.
* @param strThreadName the name of the thread, or an empty
* string if not specified.
*/
explicit Thread(const string & strThreadName = "")
{
m_strThreadName = strThreadName;
}
/**
* Destruction method.
*/
virtual ~Thread() {
if(IsAlive()) { // Do "thread-leak" checking.
// We can throw nothing from ~X(). And we'd better not to
// terminitate it, to avoid resources leak(especially
// lock-leaks/dead-lock problems caused by auto-lock).
OnLeaking();
}
}
private:
/**
* The run method should be overrided by the derived classes to
* implement the practical processing.
*/
virtual void Run() {
}
/**
* Callback method, to be called when exception occurred.
* @param pAex If it is not NULL, it points a Exception object. It
* is NULL when the exception is caught in catch-any block.
*/
virtual void OnException(const Exception * pAex) {
}
/**
* Callback method, to be called during destructing when
* detecting that the thread has not ended.
*/
virtual void OnLeaking() throw () {
}
/**
* The thread routine fuction is called by the OS's thread
* instance.
* @param pParam the pointer to the thread object which
* is created.
* @return 0 if the routine ended normally, or -1 when
* some error occurred.
*/
static int Thread_Function(Thread * pThread) {
try {
pThread->Run();
} catch(const Exception & ex) { // Exception occurred.
pThread->OnException(&ex);
return -1;
} catch(...) { // Exception occurred.
pThread->OnException(NULL);
return -1;
}
return 0;
}
public:
/**
* Cause the caller thread to block for some time.
* @param iMilliseconds the milliseconds to block.
*/
static void Sleep(int iMilliseconds) {
return ThreadImpl::Sleep(iMilliseconds);
}
public:
/**
* Cause the thead to be really created and launched to run.
* @param cbStackSize the stack size of the thread, in bytes.
* @throws ThreadCreateException throwed when failed to create
* the thread.
*/
virtual void Start(size_t cbStackSize = DEFAULT_STACK_SIZE) {
bool bRes = ThreadImpl::CreateThread(m_ts,
Thread_Function,
cbStackSize,
static_cast<Thread *>(this));
if(!bRes) {
throw ThreadCreateException("Calling CreateThread failed.");
}
}
/**
* Wait for the thread to end. If the thread is alive, the caller
* thread will be blocked until the thread ends or the specified
* timeout occurs.
* @param iTimeout the timeout, in milliseconds, of trying to
* wait until the thread ends. A value of WAIT_INFINITE casues a
* wait of infinite time.<P>
* If the thread object is invalid or has already ended, the
* method will return immediately whitout blocking.
* @return ture if the thread has ended, or not been created yet, or
* the thread is not valid. false if the timeout occurred.
*
*/
virtual bool WaitForEnd(int iTimeout = WAIT_INFINITE) {
if(!ThreadImpl::IsAlive(m_ts)) {
return true;
}
if(!ThreadImpl::WaitForThreadEnd(m_ts, iTimeout)) {
return false;
}
ThreadImpl::DestroyThread(m_ts);
return true;
}
/**
* Terminate the thread forcely.
*/
virtual void Terminate() {
ThreadImpl::TerminateThread(m_ts);
ThreadImpl::DestroyThread(m_ts);
}
/**
* Check if the thread is alive.
* @return true if the thread is valid and current running,
* or false if it is invalid or has already ended.
*/
virtual bool IsAlive() const {
return ThreadImpl::IsAlive(m_ts);
}
/**
* Get the thread's name.
* @return the thread's name.
*/
string GetName () const {
return m_strThreadName;
}
/**
* Get the thread's Id.
* @return the thread's Id.
*/
int GetId() const {
return ThreadImpl::GetThreadId(m_ts);
}
private:
// Prevent copy constructing.
Thread(const Thread &) throw();
void operator=(const Thread &);
}; // class Thread
#endif // #ifndef THREAD_H
//---- EOF ----
另外给出类Exception的代码:
//---- Exception.h ----
#ifndef EXCEPTION_H
#define EXCEPTION_H
#include <exception>
#include <string>
using std::exception;
using std::string;
class Exception : public exception {
public:
explicit Exception (const string & strMsg = "")
: m_strMsg(strMsg) {
}
virtual ~Exception() throw () {
}
virtual const char * what() const throw () {
return m_strMsg.c_str();
}
private:
string m_strMsg; // the stored message string
};
#endif // #ifndef EXCEPTION_H
//---- EOF ----
完成线程类接口代码
上一篇文章中我们详细介绍了线程类的具体实现。本篇文章完成线程类接口类的代码。
一、使用条件编译预处理指令控制跨平台代码
因为我们的类库文件都是头文件的形式,所以它们总是以源代码形式和用户文件一起被编译,这样我们可以很方便地使用编译预处理在类库文件中控制跨平台代码。
大体上,平台控制代码具有下面的形式:
#if defined(LINUX)
#include <ThreadImpl_LINUX.h>
#elif defined(WIN32)
#include <ThreadImpl_WIN32.h>
#else
#error "Not supported OS type"
#endif // #if defined(LINUX)
另外需要说明的是,我们希望尽量把这种跨平台控制代码限制在类库层次,也就是说不希望它们出现在用户的源代码中,这样从根本上保证了用户代码的平台无关性。
二、将线程的例程函数定义为类静态成员函数
首先我们不能使用非静态成员函数作为线程的例程,因为这种成员函数被编译后产生的目标代码都会自动含有一个this指针,这与线程的例程函数的定义规格不符;我们可以使用全局函数或者局部函数(C++风格的局部函数是使用无名的命名空间---Unnamed namespaces限制函数,C风格的局部函数是使用static关键字),也可以使用类的静态函数。我们使用类静态函数,以增加它与线程类的关联性:
static int Thread_Function(Thread * pThread);
三、在析构函数中检测线程泄漏
我们在线程类的析构函数中检测线程的泄漏。具体说明请参考前面的文章。
四、完整的代码
(考虑到语言通用性,使用英语的注释)
//---- Thread.h ----
#ifndef THREAD_H
#define THREAD_H
#if defined(LINUX)
#include <ThreadImpl_LINUX.h>
#elif defined(WIN32)
#include <ThreadImpl_WIN32.h>
#else
#error "Not supported OS type"
#endif // #if defined(LINUX)
#include <string>
#include <Exception.h>
using std::string;
/**
*
*/
class ThreadException : public Exception {
public:
ThreadException(const string & strMsg = "")
: Exception(strMsg) {
}
};
/**
*
*/
class ThreadCreateException : public Exception {
public:
ThreadCreateException(const string & strMsg = "")
: Exception(strMsg) {
}
};
class ThreadImpl;
/**
* This class provides the methods on threads operations. Because
* most of thread modeles are firmly OS-dependent, so the class just
* provides a basic "synchronized thread model", and omits many
* other characteristics related to some specific OSes, if there
* is any.
*/
class Thread
{
public:
static const int WAIT_INFINITE = ThreadImpl::WAIT_INFINITE;
static const int INVALID_THREAD_ID = ThreadImpl::INVALID_THREAD_ID;
static const size_t DEFAULT_STACK_SIZE = ThreadImpl::DEFAULT_STACK_SIZE;
protected:
/**
* Internal thread information structure.
*/
ThreadImpl::ThreadStruct m_ts;
/**
* The name of the thread, or "" for unnamed.
*/
string m_strThreadName;
public:
/**
* Construction method.
* @param strThreadName the name of the thread, or an empty
* string if not specified.
*/
explicit Thread(const string & strThreadName = "")
{
m_strThreadName = strThreadName;
}
/**
* Destruction method.
*/
virtual ~Thread() {
if(IsAlive()) { // Do "thread-leak" checking.
// We can throw nothing from ~X(). And we'd better not to
// terminitate it, to avoid resources leak(especially
// lock-leaks/dead-lock problems caused by auto-lock).
OnLeaking();
}
}
private:
/**
* The run method should be overrided by the derived classes to
* implement the practical processing.
*/
virtual void Run() {
}
/**
* Callback method, to be called when exception occurred.
* @param pAex If it is not NULL, it points a Exception object. It
* is NULL when the exception is caught in catch-any block.
*/
virtual void OnException(const Exception * pAex) {
}
/**
* Callback method, to be called during destructing when
* detecting that the thread has not ended.
*/
virtual void OnLeaking() throw () {
}
/**
* The thread routine fuction is called by the OS's thread
* instance.
* @param pParam the pointer to the thread object which
* is created.
* @return 0 if the routine ended normally, or -1 when
* some error occurred.
*/
static int Thread_Function(Thread * pThread) {
try {
pThread->Run();
} catch(const Exception & ex) { // Exception occurred.
pThread->OnException(&ex);
return -1;
} catch(...) { // Exception occurred.
pThread->OnException(NULL);
return -1;
}
return 0;
}
public:
/**
* Cause the caller thread to block for some time.
* @param iMilliseconds the milliseconds to block.
*/
static void Sleep(int iMilliseconds) {
return ThreadImpl::Sleep(iMilliseconds);
}
public:
/**
* Cause the thead to be really created and launched to run.
* @param cbStackSize the stack size of the thread, in bytes.
* @throws ThreadCreateException throwed when failed to create
* the thread.
*/
virtual void Start(size_t cbStackSize = DEFAULT_STACK_SIZE) {
bool bRes = ThreadImpl::CreateThread(m_ts,
Thread_Function,
cbStackSize,
static_cast<Thread *>(this));
if(!bRes) {
throw ThreadCreateException("Calling CreateThread failed.");
}
}
/**
* Wait for the thread to end. If the thread is alive, the caller
* thread will be blocked until the thread ends or the specified
* timeout occurs.
* @param iTimeout the timeout, in milliseconds, of trying to
* wait until the thread ends. A value of WAIT_INFINITE casues a
* wait of infinite time.<P>
* If the thread object is invalid or has already ended, the
* method will return immediately whitout blocking.
* @return ture if the thread has ended, or not been created yet, or
* the thread is not valid. false if the timeout occurred.
*
*/
virtual bool WaitForEnd(int iTimeout = WAIT_INFINITE) {
if(!ThreadImpl::IsAlive(m_ts)) {
return true;
}
if(!ThreadImpl::WaitForThreadEnd(m_ts, iTimeout)) {
return false;
}
ThreadImpl::DestroyThread(m_ts);
return true;
}
/**
* Terminate the thread forcely.
*/
virtual void Terminate() {
ThreadImpl::TerminateThread(m_ts);
ThreadImpl::DestroyThread(m_ts);
}
/**
* Check if the thread is alive.
* @return true if the thread is valid and current running,
* or false if it is invalid or has already ended.
*/
virtual bool IsAlive() const {
return ThreadImpl::IsAlive(m_ts);
}
/**
* Get the thread's name.
* @return the thread's name.
*/
string GetName () const {
return m_strThreadName;
}
/**
* Get the thread's Id.
* @return the thread's Id.
*/
int GetId() const {
return ThreadImpl::GetThreadId(m_ts);
}
private:
// Prevent copy constructing.
Thread(const Thread &) throw();
void operator=(const Thread &);
}; // class Thread
#endif // #ifndef THREAD_H
//---- EOF ----
另外给出类Exception的代码:
//---- Exception.h ----
#ifndef EXCEPTION_H
#define EXCEPTION_H
#include <exception>
#include <string>
using std::exception;
using std::string;
class Exception : public exception {
public:
explicit Exception (const string & strMsg = "")
: m_strMsg(strMsg) {
}
virtual ~Exception() throw () {
}
virtual const char * what() const throw () {
return m_strMsg.c_str();
}
private:
string m_strMsg; // the stored message string
};
#endif // #ifndef EXCEPTION_H
//---- EOF ----