标准C++与线程
标准C++和标准库中没有对线程的封装,程序员们不得不使用OS提供的API来处理线程,OS级别的API通常基于C,能用,但并不方便。最近看到论坛上有人问,顺便和同事讨论这个问题,如何使用标准C++封装线程的操作,目的就是易做图 and easy to use。想想自己似乎多年前(已经结易做图网了)写过这方面的代码,找了找,还真找到了,是Windows平台的,整理一下,与大家分享。
// 抽象类,作为线程类的基类,定义了几个接口
// abstract class to provide inte易做图ce.
//
class GeneralThread
{
public:
virtual ~GeneralThread() {}
public:
// create thread and run with specified priority
virtual void Run( long priority = THREAD_PRIORITY_BELOW_NORMAL ) = 0;
// wait thread running till timeout
virtual unsigned long Join( unsigned long ms = INFINITE ) = 0;
virtual unsigned long GetExitCode() const = 0;
// end thread ingore thread status.
virtual void End() {}
};
typedef GeneralThread GThread;
typedef GThread * CThreadPtr;
// 一个子类,实现了基类的接口,并且定义了一个新的接口来运行真正的线程函数
// 因此,可以从这个类继续派生新的子类,实现自定义的线程函数。
// a derived calss from GeneralThread
//
class SomeThread : public GeneralThread
{
public:
SomeThread() : m_hThread(0)
{
}
~SomeThread()
{
//Join( INFINITE );
if( m_hThread )
{
CloseHandle( m_hThread );
m_hThread = NULL;
}
}
public:
// new inte易做图ce to implement thread actions
virtual unsigned long ThreadProc() = 0;
public:
virtual void Run( long priority )
{
m_hThread = CreateThread( NULL, 0, &SomeThread::ThreadProc, this, CREATE_SUSPENDED, NULL );
if( m_hThread )
{
SetThreadPriority( m_hThread, priority );
ResumeThread( m_hThread );
}
else
{
DWORD dw = GetLastError();
UNREFERENCED_PARAMETER( dw );
}
}
virtual unsigned long Join( unsigned long ms )
{
unsigned long ul = WAIT_OBJECT_0;
if( m_hThread )
{
ul = WaitForSingleObject( m_hThread, ms );
switch( ul )
{
case WAIT_OBJECT_0:
//GetExitCodeThread( m_hThread, &m_exitCode );
break;
case WAIT_TIMEOUT:
break;
case WAIT_FAILED:
ul = ul;
break;
}
}
return ul;
}
virtual unsigned long GetExitCode() const
{
DWORD exitCode = 0;
GetExitCodeThread( m_hThread, &exitCode );
return exitCode;
}
virtual void End()
{
TerminateThread( m_hThread, 0xabcd );
}
private:
static unsigned long WINAPI ThreadProc( LPVOID lpParameter )
{
SomeThread *p = static_cast< SomeThread * >( lpParameter );
return p->ThreadProc();
}
private:
HANDLE m_hThread;
};
// 虽然可以从SomeThread 派生子类,但是如果有多个线程,并且每个线程的线程函数不一样的话,
// 那么需要实现多个子类,并不是很方便。考虑到标准C++推荐使用模板和函数对象,因此派生了一个
// 子类,重新实现了父类中的虚函数,转发成对函数对象的访问。
//
// if you want to implement your thread, you have to derive a class from SomeThread and also implement your thread procedure.
// sometimes you will feel boring.
// so here we implement a template class to simplify usage.
// thus you don't need to code your derived class, instead just provide your function object.
//
template< typename F >
class ConcreteThread : public SomeThread
{
public:
ConcreteThread( const F &f ) : m_f(f)
{
}
private:
unsigned long ThreadProc()
{
return m_f();
}
private:
F m_f;
};
template< typename F >
CThreadPtr MakeThread( F &f )
{
return new ConcreteThread< F >( f );
}
// 这个类提供了另一种形式的封装。
// this class is just for 易做图 usage in stack scope.
//
class Thread
{
public:
template< typename F >
Thread( F &f ) : m_pThread( MakeThread(f) )
{
m_pThread->Run();
}
~Thread()
{
delete m_pThread;
}
public:
unsigned long Join()
{
return m_pThread->Join();
}
unsigned long ExitCode()
{
return m_pThread->GetExitCode();
}
private:
CThreadPtr m_pThread;
};
代码不长,而且加了些注释,不难理解。下面是测试用的代码
int sum( int end )
{
int sum = 0;
for( int i = 0 ; i < end ; i++ )
{
sum += i;
}
return sum;
}
void TestThread()
{
// test Thread class
Thread t( std::bind( sum, 10000 ) ), t2( std::bind( sum, 20000 ) );
t.Join();
t2.Join();
std::cout << "sum1 = " << t.ExitCode() << "; sum2 = " << t2.ExitCode() << std::endl;
// test ConcreteThread
CThreadPtr p = MakeThread( std::bind( sum, 50000 ) );
p->Run();
p->Join();
std::cout << "sum3 = " << p->GetExitCode() << std::endl;
//delete p;
std::auto_ptr< GeneralThread > p2( MakeThread( std::bind( sum, 50001 ) ) );
p->Run(); p->Join();
std::cout <<"sum4 = " << p->GetExitCode() << std::endl;
}
测试代码很简短,使用了标准C++的std::bind把sum函数包装成函数对象,然后在单独的线程中运行。
一般而言,使用C++封装系统API以方便使用,通常难度不大,代码也不会太长。这是一个典型的例子。
补充:软件开发 , C++ ,