4.2.2.1 鎖(lock)類屬

4.2.2.1 鎖(lock)類屬

標籤lock  2008-12-07 13:47
4.2.2.1 鎖(lock)類屬

 Mutex / Thread_Mutex / Process_Mutex  互斥體. 獲得它的線程才能進入臨界區.
  // 例子代碼 : Thread_Mutex 類的用win32 api的簡單實現:
  class Thread_Mutex {
  public:
   Thread_Mutex ( ) {
    InitializeCriticalSection (&lock_);
   }
   ~Thread_Mutex ( ) {
    DeleteCriticalSection (&lock_);
   }
   int acquire ( ) {  //獲取對互斥體的鎖定
    EnterCriticalSection (&lock_); return 0;
   }
   int release ( ) {  //釋放鎖定
    LeaveCriticalSection (&lock_); return 0;
   }
  private:
   // Win32 serialization mechanism.
   CRITICAL_SECTION lock_;
  };

 RW_Mutex / RW_Thread_Mutex / RW_Process_Mutex 讀寫互斥體. 用在讀多寫少的情況下.

 Semaphore / Thread_Semaphore / Process_Semaphore  信號量. 通過原子的增減一個整數來管理.
  // 例子代碼: Semaphore的簡單實現:
  class Semaphore {
  public:
   Semaphore (int initial_value): count_nonzero_ (lock_) {
    Guard<Thread_Mutex> monitor (lock_);
    count_ = initial_value;
   }
   void acquire (void) {
    Guard<Thread_Mutex> monitor (lock_);
    while (count_ == 0)
     count_nonzero_.wait ();  //當信號量的計數爲0時. 等待.
    count_ = count_ - 1;
   }
   void release (void) {
    Guard<Thread_Mutex> monitor (lock_);
    if (count_ == 0)
     count_nonzero_.signal ();
    count_ = count_ + 1;
   }
   private:
    Thread_Mutex lock_;
    Condition<Thread_Mutex> count_nonzero_;  //通過條件對象實現
    u_int count_;
   };

 Null_Mutex  一種0開銷的互斥體(它的鎖定/解鎖函數是空的內聯函數. 所以沒有運行時開銷. 用在不需要同步的情況下
  //例子代碼: Null_Mutex類的簡單實現:
  class Null_Mutex {
  public:
   Null_Mutex (void) {}
   ~Null_Mutex (void) {}
   int remove (void) { return 0; }
   int acquire (void) const { return 0; }
   int try_acquire (void) const { return 0; }
   int release (void) const { return 0; }
  };

 Token 令牌環. 它和Mutex相比更爲通用. 因爲它實現了"遞歸互斥體"語義(擁有鎖的線程可以重新獲得該鎖). 並且它對阻塞在該
  令牌環上的線程以FIFO(先進先出)的順序被服務(而Mutex沒有這種順序). 
  // Token的接口如下:
  class Token {
  public:
   Token (const char *name = 0, void * = 0);
   ~Token (void);
   int acquire (void (*sleep_hook)(void *),
   void *arg = 0,
   Time_Value *timeout = 0);
   int acquire (Time_Value *timeout = 0);
   virtual void sleep_hook (void);
   int renew (int requeue_position = 0, Time_Value *timeout = 0);
   int tryacquire (void);
   int remove (void);
   int release (void);
   int waiters (void);
   thread_t current_owner (void);
  };   

 Recursive_Thread_Mutex 這個類貌似只用在Solaris中. 因爲Solaris缺省提供的互斥體是非遞歸的(即擁有該鎖的線程不可以再次
  獲得該鎖). 所以提供了這個類. (在Win32和 POSIX Pthreads中提供的是遞歸鎖. 不存在這個問題).  
  
 
4.2.2.2 Guard類屬

 Guard / Write_Guard / Read_Guard 用它的構造函數和析構函數來 獲取和釋放 鎖.
  // 例子代碼. Guard類的簡單實現:
  class Guard {  
  public:
   Guard(const Thread_Mutex & m) : lock_(m) {
    lock_.acquire(); //讓鎖定和解鎖自動化
   }
   ~Guard() {
    lock_.release();
   }
  private:
   const Thread_mutex & lock_;
  };

 Thread_Control  不知作用....以後補....
 
4.2.2.3 Condition類屬
 Condition  條件. 應該和Java中 java.util.concurrent.locks.Condition 的作用一樣.
 Null_Condition  它提供了0開銷的Condition實現. 用來在不需要同步的時候使用(和Null_Mutex類似).
  // Condition類的接口 :
  template <class MUTEX>
  class Condition {
  public:
   Condition(const MUTEX &m, int type = USYNC_THREAD, void *arg = 0); //通過鎖來構造條件對象.
   ~Condition();
   int remove();  //要這個函數幹啥???
   int wait(Time_Value *abstime = 0) const;  // 等待
   int signal() const;  //通知一個等待的線程.
   int broadcast() const; //通知所有等待線程.
  }


 
4.2.2.6 其它類屬

 Thread  線程類  這個類中的一些靜態函數用於線程的創建等.
   它是一個原始的東西. 通常應該使用Thread_Manager類而不是它.

 atomic_Ops  封裝了對於內置數據類型(如int)的算術操作(如++).  使這種操作成爲線程安全的(原子的).
   //例子代碼
   template <class TYPE>
   class Atomic_Op {
   public:
    Atomic_Op (void) { count_ = 0; }
    Atomic_Op (TYPE c) { count_ = c; }
    TYPE operator++ (void)  { //封裝了內置類型的算術運算. 使它成爲線程安全的.(還有其它的類似++的運算符)
     Guard monitor (lock_);
     return ++count_;
    }
    operator TYPE () {  //取內部數據類型的值. 返回的是該數據當前值的拷貝.
     Guard monitor_ (lock_);
     return count_;
    }
    // Other arithmetic operations omitted...
   private:
    Thread_Mutex lock_;
    TYPE count_;
   };
   

4.5.4 ACE線程管理器類

4.5.4.1 Thread_Manager類.  //這節的筆記來自<<中篇: ACE程序員教程>> 4.3節
 它用來管理成組的線程 和 任務(ACE_Task). 
 它比ACE_Thread類的功能更多. 它不僅可以創建/銷燬一組線程. 還可以對它們掛起和恢復.
 也可以發送信號給某一組線程. 或者是在一組線程上等待.
 這個類使用了單件模式. 用 ACE_Thread_Manager* Thr_Manager = ACE_Thread_Manager::instance() 來取得該對象.
 
 /////////////////////////////////////////////////////////////////////
 // 使用Thread_Manager來管理線程的例子. (來自<<ACE程序員教程>>49頁)
 /////////////////////////////////////////////////////////////////////

 
 // 演示怎麼使用ACE_Thread_Manager類來對線程組進行 掛起/恢復
 // 以及協作式撤銷(就是對線程設置一個狀態.讓該線程的代碼檢測該狀態後退出).
 
 #include "ace/Thread_Manager.h"
 
 static const int DEFAULT_THREADS = ACE_DEFAULT_THREADS;
 static const int DEFAULT_ITERATIONS = 100000;
 
 static void * worker (int iterations) { 
  for (int i = 0; i < iterations; i++) {
   if ((i % 1000) == 0) {  //每循環1000次檢測一下"當前線程是否正請求撤銷".
    ACE_DEBUG ((LM_DEBUG, "(%t) checking cancellation before iteration %d!/n", i));
    //用單件ACE_Thread_Manager對象的testcancel()來測試是否撤銷一個線程.
    // 所以看上去ACE_Thread::self()可以取得當前正在執行的線程(ACE_thread_t).
    if (ACE_Thread_Manager::instance ()->testcancel (ACE_Thread::self ()) != 0) {
     ACE_DEBUG ((LM_DEBUG, "(%t) has been canceled before iteration %d!/n",i));
     break;
    }
   }
  }
  return 0;
 }
 int main (int argc, char *argv[])
 {
  int n_threads = argc > 1 ? ACE_OS::atoi (argv[1]) : DEFAULT_THREADS;  //線程數
  int n_iterations = argc > 2 ? ACE_OS::atoi (argv[2]) : DEFAULT_ITERATIONS;  //線程函數中的循環的次數.
  
  ACE_Thread_Manager *thr_mgr = ACE_Thread_Manager::instance ();  //取得單件的線程管理器對象
  
  // 下邊的 ACE_Thread_Manager::spawn_n()創建的是一組線程們.
  // 在本例子中是創建一組共n_threads個線程.
  // 這一組線程都執行第2個參數指定的線程函數.
  // 第3個參數指定將要傳遞給線程函數的參數. 第4個是一些旗標. 默認THR_NEW_LWP|THR_JOINABLE|THR_INHERIT_SCHED.
  // 還有其它一些參數. 指定線程堆棧. 優先級等. 這個函數除了前兩個參數外都有默認值.
  // 它返回創建的這個線程組的組ID.
  int grp_id = thr_mgr->spawn_n (
   n_threads,  //這個線程組的線程數
   ACE_THR_FUNC (worker),  //這組線程的線程函數
   (void *) n_iterations,  // 傳遞給線程函數的參數.
   THR_NEW_LWP | THR_DETACHED); //旗標.
   
  ACE_OS::sleep (1);   //主線程休息1秒.
  
  ACE_DEBUG ((LM_DEBUG, "(%t) suspending group/n"));
  if (thr_mgr->suspend_grp (grp_id) == -1) //讓一組線程掛起
   ACE_ERROR ((LM_DEBUG, "(%t) %p/n", "Could not suspend_grp"));
   
  ACE_OS::sleep (1);
  ACE_DEBUG ((LM_DEBUG, "(%t) resuming group/n"));
  if (thr_mgr->resume_grp (grp_id) == -1)  // 讓一組線程喚醒
   ACE_ERROR ((LM_DEBUG, "(%t) %p/n", "resume_grp"));
  // Wait for 1 more second and then cancel all the threads.
  ACE_OS::sleep (ACE_Time_Value (1));
  ACE_DEBUG ((LM_DEBUG, "(%t) canceling group/n"));
  if (thr_mgr->cancel_grp (grp_id) == -1)  // 請求一組線程撤銷. 所以線程函數中要有配合的代碼. 如worker()所示.
   ACE_ERROR ((LM_DEBUG, "(%t) %p/n", "cancel_grp"));
  //  等待線程管理器中所有的線程結束.
  thr_mgr->wait ();
  return 0;
 }

 

4.5.6 其它類

TSS(線程專有存儲)
 ACE中使用模板類ACE_TSS來解決"線程專有存儲"的問題. 它的使用很簡單:
 需要成爲線程專有的類被傳入ACE_TSS 模板. 然後可以使用C++的->操作符來調用它的全部公共方法.
 (原理是不是在該類的 operator-> 函數中先取得當前線程的句柄. 再根據線程句柄映射到該線程專有的對象上)
 ///////////////////////////////////////////////////////////
 // 使用ACE_TSS的一個例子. 來自<<ace程序員教程>>4.4節 51頁
 ///////////////////////////////////////////////////////////
 #include "ace/Synch.h"
 #include "ace/Thread_Manager.h"
 class DataType {
 public:
  DataType():data(0){}
  void increment(){ data++;}
  void set(int new_data){ data=new_data;}
  void decrement(){ data--;}
  int get(){return data;}
 private:
  int data;
 };

 // 構造全局的線程專有對象. 是不是很簡單?
 ACE_TSS<DataType> data; 
 
 // 測試線程1. 其中使用全局的 data. 但實際上它們使用的是各自的線程專有的.
 static void* thread1(void*) {
  data->set(10);
  ACE_DEBUG((LM_DEBUG,"(%t)The value of data is %d /n",data->get()));
  for(int i=0;i<5;i++)
  data->increment();
  ACE_DEBUG((LM_DEBUG,"(%t)The value of data is %d /n",data->get()));
  return 0;
 }
 
 // 測試線程2. 其中使用全局的data. 但實際上它們使用的是各自的線程專有的.
 static void * thread2(void*) {
  data->set(100);
  ACE_DEBUG((LM_DEBUG,"(%t)The value of data is %d /n",data->get()));
  for(int i=0; i<5;i++)
  data->increment();
  ACE_DEBUG((LM_DEBUG,"(%t)The value of data is %d /n",data->get()));
  return 0;
 }
 
 int main(int argc, char*argv[]) {
  // 注意這裏的ACE_Thread_Manager::spawn()函數. 它和spawn_n()很相似. 但它只創建一個線程.
  ACE_Thread_Manager::instance()->spawn((ACE_THR_FUNC)thread1,0,THR_NEW_LWP|THR_DETACHED);
  ACE_Thread_Manager::instance()->spawn((ACE_THR_FUNC)thread2,0,THR_NEW_LWP| THR_DETACHED);
  // 等待線程管理器中所有的線程結束.
  ACE_Thread_Manager::instance()->wait();
  ACE_DEBUG((LM_DEBUG,"Both threads done.Exiting.. /n"));
 }

發佈了12 篇原創文章 · 獲贊 4 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章