程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 標准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以方便使用,通常難度不大,代碼也不會太長。這是一個典型的例子。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved