当前位置:编程学习 > C/C++ >>

标准C++与线程

标准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以方便使用,通常难度不大,代码也不会太长。这是一个典型的例子。

补充:软件开发 , C++ ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,