乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      C++:多線程類庫的設(shè)計與實現(xiàn)(六)

       just_person 2012-03-15
      線程類的具體實現(xiàn)

      一、將接口和實現(xiàn)相分離

      分離接口和實現(xiàn)是OO設(shè)計中的重要思想。它其實反映了現(xiàn)實世界中抽象和具象、一般和特殊的基本現(xiàn)象和規(guī)律。而我們,正是基于這種思想,來完成我們類庫的跨平臺特性。

      基本上所有的OO開發(fā)環(huán)境都提供了支持接口和實現(xiàn)分離的機制。很多機制是基于編程語言本身的,如可繼承性和多態(tài)性,而有些機制還基于體系結(jié)構(gòu)特性,比如CORBA和COM。

      我們把有關(guān)線程的具體實現(xiàn)封裝到“實現(xiàn)類”里面,命名為TheadImpl。實際上ThreadImpl只是一個薄層封裝,為上層Thread類提供一個統(tǒng)一線程API調(diào)用界面。

      二、包裝系統(tǒng)的API

      雖然只是一個薄層封裝,我們不得不做常常是讓類庫設(shè)計者最頭疼的一件事情---統(tǒng)一操作系統(tǒng)API的調(diào)用界面。每種操作系統(tǒng)都提供API,常常都是相互風(fēng)格迥異,這給統(tǒng)一包裝API界面帶來很多困難---雖然同時也增加了這項工作的藝術(shù)性。設(shè)計者不得不充分調(diào)研各種對象操作系統(tǒng),了解每個API的調(diào)用規(guī)格,詳細歸納,慎重取舍,以設(shè)計出良好的統(tǒng)一包裝界面。在這里系統(tǒng)編程經(jīng)驗至關(guān)重要。

      雖然本系列的文章順序是先介紹線程類Thread的接口,再來討論ThreadImpl的具體實現(xiàn),這可能會給讀者帶來自上而下(Top down)的設(shè)計路線的印象。而實際上,和許多工作的實際過程一樣,C++類庫設(shè)計也不是簡單的自上而下或者自下而上(Bottom up),而是一個PDCA循環(huán)(規(guī)劃 Plan-執(zhí)行 DO-檢查 Check-措施 Action)。據(jù)我的個人經(jīng)驗,每個類庫在第一版設(shè)計完成后都要經(jīng)過重復(fù)數(shù)次的修改,以達到一個相對穩(wěn)定的版本。

      以上的經(jīng)驗之談是希望讀者能理解和大多數(shù)工作一樣C++類庫設(shè)計也不是一件一蹴而就的直線性工作。下面介紹我們的對象系統(tǒng)的線程API---我們的包裝對象。

      三、盤點POSIX與Windows的線程API
      和其他POSIX系統(tǒng)API一樣,POSIX線程的API在POSIX規(guī)范 IEEE 1003系列中被定義,目前的版本為2004年版。POSIX線程提供豐富的系統(tǒng)調(diào)用,不過我們的線程類只使用其中的一部分。如果讀者手頭沒有IEEE的文檔也沒有關(guān)系,因為POSIX線程被廣泛實現(xiàn)于各種Linux平臺,絕大多數(shù)Linux系統(tǒng)的手冊頁(Manual page)都有相關(guān)的敘述。

      創(chuàng)建線程:

      POSIX:
      int pthread_create (
           pthread_t *restrict thread,
           const pthread_attr_t *restrict attr,
           void *(*start_routine)(void*), 
           void *restrict arg
      );

      pthread_create()創(chuàng)建線程并立刻執(zhí)行它。


      Windows:
      HANDLE CreateThread(
            LPSECURITY_ATTRIBUTES lpThreadAttributes,
            SIZE_T dwStackSize,
            LPTHREAD_START_ROUTINE lpStartAddress,
            LPVOID lpParameter,
            DWORD dwCreationFlags,
            LPDWORD lpThreadId
      );

      CreateThread()允許在dwCreationFlags參數(shù)中指定線程是否以掛起狀態(tài)被創(chuàng)建(CREATE_SUSPENDED標(biāo)志)。另外CreateThread允許通過dwStackSize指定線程初始棧大小。

      這兩個函數(shù)都接受一個用戶例程函數(shù)指針,作為線程運行的用戶代碼入口。

      用戶例程的形式定義:
      POSIX:
      void * start_routine(void * param);

      Windows:
      DWORD WINAPI ThreadProc(LPVOID lpParameter);

      設(shè)置線程初始棧:

      Posix:
      通過線程屬性設(shè)定。

      int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);

      Windows:
      在CreateThread()中指定。

      判斷線程死活/有效性

      POSIX:
      IEEE 1003中并沒有明確指定判斷線程死活的API。不過很多人使用pthread_kill():
      int pthread_kill(pthread_t thread, int sig);

      通過發(fā)送信號0來測試線程的有效性。這樣的做的依據(jù)可能來源于標(biāo)準(zhǔn)IEEE 1003關(guān)于pthread_kill()的一段注釋:
      “Upon successful completion, the function shall return a value of zero. The pthread_kill ( ) function shall request that a signal be delivered to the specified thread. As in kill( ), if sig is zero, error checking shall be performed but no signal shall actually be sent.”

      另外規(guī)范中對于pthread_kill()的返回值定義如下:
      [ESRCH] No thread could be found corresponding to that specified by the given thread ID.
      [EINVAL] The value of the sig argument is an invalid or unsupported signal number.

      調(diào)用pthread_kill,發(fā)送信號0,檢測pthread_kill的返回值。如果pthread_t型的ID指向一個有效并且執(zhí)行中的線程,則pthread_kill應(yīng)該返回0;如果是一個無效ID或者線程已經(jīng)結(jié)束,則pthread_kill應(yīng)該返回ESRCH。

      這看起來是個不錯的辦法,可惜筆者在實踐中發(fā)現(xiàn),在某些POSIX實現(xiàn)(具體的說是Cygwin的某些版本)中,調(diào)用pthread_kill并傳遞一個無效的線程ID將直接導(dǎo)致指針操作異常而使程序異常結(jié)束。

      筆者發(fā)現(xiàn)使用另一個API好像更為安全:

      int pthread_getschedparam(
          pthread_t thread, 
          int *restrict policy,
          struct sched_param *restrict param
      );

      pthread_getschedparam()有類似的調(diào)用語義規(guī)范:

      “RETURN VALUE
      If successful, the pthread_getschedparam( ) and pthread_setschedparam( ) functions shall return zero; otherwise, an error number shall be returned to indicate the error.
      The pthread_getschedparam() function may fail if:
       [ESRCH] The value specified by thread does not refer to an existing thread.”

      所以,在我們的版本中,用pthread_getschedparam取代pthread_kill來測試線程死活。pthread_getschedparam的這一用途在筆者所測試的Cygwin和Linux版本中發(fā)揮正常。

      Windows:
      DWORD WaitForSingleObject(
            HANDLE hHandle,
            DWORD dwMilliseconds
      );

      Windows編程的規(guī)范做法,是調(diào)用WaitForSingleObject,指定等待時間為0。如果返回值為WAIT_TIMEOUT則說明線程為有效,否則為無效線程HANDLE或者線程已經(jīng)結(jié)束。

      線程的睡眠函數(shù):
      POSIX:
      unsigned sleep(unsigned seconds); 
      int usleep(useconds_t useconds);

      這兩個API提供不同時間粒度的睡眠。我們可以把它們組合起來以實現(xiàn)毫秒級粒度的睡眠功能。另外某些老版本的Linux實現(xiàn)中把sleep()和usleep()解釋為進程級別的睡眠API---這已經(jīng)過時了。根據(jù)IEEE 1003 2004的說明:
      “The sleep( ) function shall cause the calling thread to be suspended from execution until either the number of realtime seconds specified by the argument seconds has elapsed or a signal is delivered to the calling thread and its action is to invoke a signal-catching function or to terminate the process.”

      usleep也有內(nèi)似的說明。目前的流行Linux版本的sleep和usleep都是線程級別的。

      Windows:

      VOID Sleep(DWORD dwMilliseconds); 

      強行結(jié)束線程:
      POSIX:
      int pthread_cancel(pthread_t thread);

      Windows:
      BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode);

      程序員應(yīng)該盡量避免調(diào)用強行結(jié)束線程的API,尤其是在C++程序設(shè)計中。我們將在后續(xù)的文章中解釋其原因。

      四、完成線程實現(xiàn)類的代碼
      下面給出POSIX線程實現(xiàn)類代碼。代碼中使用了Java風(fēng)格的注釋。

      //---- ThreadImpl_Linux.h----

      #ifndef THREAD_IMPL_LINUX_H
      #define THREAD_IMPL_LINUX_H

      #include <pthread.h>
      #include <unistd.h>

      class Thread;

      /**
       * Linux(POSIX)版本的線程實現(xiàn)類。
      */
      class ThreadImpl  
      {

      public:
          static const int        WAIT_INFINITE            = -1;
          static const int        INVALID_THREAD_ID        = 0;
          static const size_t     DEFAULT_STACK_SIZE       = 0;
          static const int        WAIT_TIME_SLICE          = 10;
          
          
      public:

          /**
           * 線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體。包含線程的平臺相關(guān)信息。
           */
          struct ThreadStruct {
              pthread_t     tThread;
              
              ThreadStruct() 
                  :
                  tThread(INVALID_THREAD_ID)
                  
              {
              }

              ~ThreadStruct() {
              }
          };
          

      public:
          typedef int (* THREAD_FUNCTION) (Thread *pParam);
          typedef void * (*POSIX_THREAD_ROUTINE) (void *pParam);
          
      public:

          /**
           * 創(chuàng)建線程。
           * @param ts線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體型變量。
           * @param thread_func 用戶例程函數(shù)指針。
           * @param cbStackSize 線程初始棧大小,字節(jié)單位。
           * @param pThread 綁定的Thread對象指針。
           * @return 調(diào)用成功返回true,失敗返回false。
           */
          static bool CreateThread(ThreadStruct & ts, 
                          THREAD_FUNCTION thread_func,
                          size_t cbStackSize,
                          Thread * pThread) {
              
              
              pthread_attr_t *pAttr = NULL;
              pthread_attr_t attr;
              
              if(cbStackSize != DEFAULT_STACK_SIZE) {
                  
                  if(0 != pthread_attr_init(&attr)) {
                      return false;
                  }
                  
                  if(0 != pthread_attr_setstacksize(&attr, cbStackSize)) {
                      pthread_attr_destroy(&attr);
                      return false;
                  }
                  
                  pAttr = &attr;
              }
              
              int iRes = pthread_create(&(ts.tThread), 
                                  pAttr, 
                                  (POSIX_THREAD_ROUTINE)thread_func, 
                                  (void*)pThread);
                      
              if(NULL != pAttr) {
                  pthread_attr_destroy(&attr);
              }
                      
              if(0 != iRes) {
                  return false;
              }
              
              pthread_detach(ts.tThread);
              
              return true;
          }

          /**
           * 銷毀線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體。
           * @param ts 線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體型變量。
           */
          static void DestroyThread(ThreadStruct & ts) {
          }


          /**
           * 在指定時間內(nèi)等待線程結(jié)束。
           * @param ts 線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體。
           * @param iTimeout 指定的等待時間。
           * @return 線程在指定時間內(nèi)結(jié)束的情況下返回true,否則返回false。
           * 如果傳入的線程結(jié)構(gòu)體未關(guān)聯(lián)到有效線程,則返回true。
           */
          static bool WaitForThreadEnd(const ThreadStruct & ts, int iTimeout) {
              
              int iDelta = WAIT_TIME_SLICE;
              int iTotal = iTimeout;
              
              if(iTimeout == WAIT_INFINITE) { // Cause to do unlimited loop.
                  iDelta = 0;
                  iTotal = 1;
              }
              
              for(int i=0; i<iTotal; i+=iDelta) {
                  if(!IsAlive(ts)) {
                      return true;
                  } else {
                      Sleep(WAIT_TIME_SLICE);
                  }
              }
              
              return false;
          } 

          /**
           * 強行結(jié)束線程。
           * @param ts 線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體型變量。
           */
          static void TerminateThread(ThreadStruct & ts) {
              ::pthread_cancel(ts.tThread);
          }

          /**
           * 判斷線程死活。
           * @param ts 線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體型變量。
           * @return 線程為有效則返回true,否則返回false。
           */
          static bool IsAlive(const ThreadStruct & ts) {

              int iPolicy;
              struct sched_param sp;
              
              int iRes = pthread_getschedparam(ts.tThread, &iPolicy, &sp);
              
              if(0 == iRes) {
                  return true;
              } else {
                  return false;
              }
          } 
          
          /**
           * 獲取線程ID。該ID在進程域內(nèi)唯一。
           * @param ts線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體型變量。
           */
          static int GetThreadId(const ThreadStruct & ts) {
              return (int) ts.tThread;
          }

          /**
           * 導(dǎo)致調(diào)用線程被掛起若干時間。
           * @param iMs 線程掛起時間,毫秒單位。
           */
          static void Sleep(int iMs) {
              
              int iS  = iMs / 1000;
              int iUs = (iMs % 1000) * 1000;
              
              if(iS > 0) {
                  sleep(iS);
              }
              
              if(iUs > 0) {
                  usleep(iUs);
              }
              
              return;
          }
          
      private:
          // 禁止構(gòu)造函數(shù)。
          ThreadImpl();
          
          // 禁止拷貝構(gòu)造函數(shù)。
          ThreadImpl(const ThreadImpl &) throw();

          // 禁止賦值操作符。
          void operator=(const ThreadImpl &);
      }; // class ThreadImpl

      #endif // #ifndef ThreadImpl_LINUX_H

      //----EOF----


      Windows的線程實現(xiàn)類的代碼如下:

      //----ThreadImpl_WIN32.h----

      #ifndef THREAD_IMPL_WIN32_H
      #define THREAD_IMPL_WIN32_H

      #include <Windows.h>

      class Thread;

      /**
       * Windows 32位平臺版本的線程實現(xiàn)類。
       */
      class ThreadImpl  
      {


      public:
          static const int        WAIT_INFINITE            = -1;
          static const int        INVALID_THREAD_ID        = 0;
          static const size_t    DEFAULT_STACK_SIZE        = 0;

      public:
          /**
           * 線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體。包含線程的平臺相關(guān)信息。
           */
          struct ThreadStruct {
              
              HANDLE     hThread;
              DWORD    dwThreadId;
              
              ThreadStruct() 
                  :
                  hThread(NULL),
                  dwThreadId(INVALID_THREAD_ID)
              {
              }
              
              void Cleanup() {
                  if(hThread != NULL) {
                      CloseHandle(hThread);
                      hThread = NULL;
                  }
                  
              }

              ~ThreadStruct() {
                  Cleanup();
              }
          };
          
      public:
          typedef int (* THREAD_FUNCTION) (Thread *pParam);

      public:
          
          /**
           * 創(chuàng)建線程。
           * @param ts線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體型變量。
           * @param thread_func 用戶例程函數(shù)指針。
           * @param cbStackSize 線程初始棧大小,字節(jié)單位。
           * @param pThread 綁定的Thread對象指針。
           * @return 調(diào)用成功返回true,失敗返回false。
           */

          static bool CreateThread(ThreadStruct & ts, 
                          THREAD_FUNCTION thread_func,
                          size_t cbStackSize,
                          Thread * pThread) {
              

              ts.hThread = ::CreateThread(NULL, 
                          (DWORD) cbStackSize,
                          (LPTHREAD_START_ROUTINE) thread_func,
                          (LPVOID) pThread,
                          0,
                          &ts.dwThreadId);
                                  
              if(ts.hThread == NULL) {
                  return false;
              }
              
              return true;
          }

          /**
           * 銷毀線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體。
           * @param ts 線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體型變量。
           */
          static void DestroyThread(ThreadStruct & ts) {
              ts.Cleanup();    
          }


          /**
           * 在指定時間內(nèi)等待線程結(jié)束。
           * @param ts 線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體。
           * @param iTimeout 指定的等待時間。
           * @return 線程在指定時間內(nèi)結(jié)束的情況下返回true,否則返回false。
           * 如果傳入的線程結(jié)構(gòu)體未關(guān)聯(lián)到有效線程,則返回true。
           */
          static bool WaitForThreadEnd(const ThreadStruct & ts, int iTimeout) {
              
              DWORD dwTO = (DWORD) iTimeout;

              if(iTimeout == WAIT_INFINITE) {
                  dwTO = INFINITE;
              }

              DWORD dwRes = WaitForSingleObject(ts.hThread, dwTO);
              
              if(dwRes == WAIT_TIMEOUT) {
                  return false;
              } else {
                  return true;
              }
          } 

          /**
           * 強行結(jié)束線程。
           * @param ts 線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體型變量。
           */
          static void TerminateThread(const ThreadStruct & ts) {
              ::TerminateThread(ts.hThread, -1);
          }

          /**
           * 判斷線程死活。
           * @param ts 線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體型變量。
           * @return 線程為有效則返回true,否則返回false。
           */
          static bool IsAlive(const ThreadStruct & ts) {

              if(NULL == ts.hThread) {
                  return false;
              }
          
              DWORD dwRes = WaitForSingleObject(ts.hThread, 0);
              
              if(WAIT_TIMEOUT == dwRes) {
                  return true;    
              } else if(WAIT_OBJECT_0 == dwRes || WAIT_FAILED == dwRes) {
                  return false;
              } else {
                  return false;
              }
          } 
          
          /**
           * 獲取線程ID。該ID在進程域內(nèi)唯一。
           * @param ts線程實現(xiàn)類的內(nèi)部結(jié)構(gòu)體型變量。
           */
          static int GetThreadId(const ThreadStruct & ts) {
              return (int) ts.dwThreadId;
          }

          /**
           * 導(dǎo)致調(diào)用線程被掛起若干時間。
           * @param iMs 線程掛起時間,毫秒單位。
           */
          static void Sleep(int iMs) {
              return ::Sleep(iMs);
          }
          
      private:
          // 禁止構(gòu)造函數(shù)。
          ThreadImpl();
          
          // 禁止拷貝構(gòu)造函數(shù)。
          ThreadImpl(const ThreadImpl &) throw();
      // 禁止賦值操作符。
          void operator=(const ThreadImpl &);
      }; // class ThreadImpl

      #endif // #ifndef ThreadImpl_WIN32_H

      //----EOF----

      對上面的代碼稍微做一點說明。

      Linux版本的CreateThread()中,創(chuàng)建完線程后立即調(diào)用pthread_detach(),以通知POSIX線程庫可以在該線程結(jié)束時立即釋放線程資源。注意到我們不使用pthread_join()來等待線程結(jié)束。POSIX的現(xiàn)程模型使用pthread_join()來實現(xiàn)簡單的線程調(diào)度,在筆者看來用起來很不方便,因為pthread_join()只能是無限等待,不提供超時機制,大大降低了程序設(shè)計的靈活性。

      為了實現(xiàn)帶超時的線程等待函數(shù),如我們的WaitForThreadEnd(),我們不得不把等待時間分解成更小的時間片輪詢。這樣做損失了一點CPU資源,并稍微影響了超時判斷的時間精度。

      Windows版本的TerminateThread()中,我們將線程的結(jié)束代碼(Exit code)一律指定為-1。我們的上層線程類不使用這個結(jié)束代碼。

      Linux版本和Windows版本的線程實現(xiàn)類都不提供線程優(yōu)先級的相關(guān)功能。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多