标准C++和标准库中没有对线程的封装,程序员们不得不使用OS提供的API来处理线程,OS级别的API通常基于C,能用,但并不方便。最近看到论坛上有人问,顺便和同事讨论这个问题,如何使用标准C++封装线程的操作,目的就是simple and easy to use。想想自己似乎多年前(已经结蜘蛛网了)写过这方面的代码,找了找,还真找到了,是Windows平台的,整理一下,与大家分享。
- // 抽象类,作为线程类的基类,定义了几个接口
- // abstract class to provide interface.
- //
- 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 interface 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 simple 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以方便使用,通常难度不大,代码也不会太长。这是一个典型的例子。