ACE Lock類屬

http://hi.baidu.com/653701wwww/blog/item/9d787c00e961bb8fe950cdb9.html

鎖類屬包含的類包裝簡單的鎖定機制,比如互斥體、信號量、讀/寫互斥體和令牌。在這一類屬中可用的類在表4-1 中顯示。每個類名後都有對用法和用途的簡要描述:

 

名字

描述

ACE_Mutex

封裝互斥機制(根據平臺,可以是

mutex_t pthread_mutex_t 等等)的包裝類,用於提供簡單而有效的機制來使對共享資源的訪問序列化。它與二元信號量( binary semaphore )的功能相類似。可被用於線程和進程間的互斥。

ACE_Thread_Mutex

可用於替換

ACE_Mutex ,專用於線程同步。

ACE_Process_Mutex

可用於替換

ACE_Mutex ,專用於進程同步。

ACE_NULL_Mutex

提供了

ACE_Mutex 接口的“無爲”( do-nothing )實現,可在不需要同步時用作替換。

ACE_RW_Mutex

封裝讀者/作者鎖的包裝類。它們是分別爲讀和寫進行獲取的鎖,在沒有作者在寫的時候,多個讀者可以同時進行讀取。

ACE_RW_Thread_Mutex

可用於替換

ACE_RW_Mutex ,專用於線程同步。

ACE_RW_Process_Mutex

可用於替換

ACE_RW_Mutex ,專用於進程同步。

ACE_Semaphore

這些類實現計數信號量,在有固定數量的線程可以同時訪問一個資源時很有用。在

OS 不提供這種同步機制的情況下,可通過互斥體來進行模擬。

ACE_Thread_Semaphore

應被用於替換

ACE_Semaphore ,專用於線程同步。

ACE_Process_Semaphore

應被用於替換

ACE_Semaphore ,專用於進程同步。

ACE_Token

提供“遞歸互斥體”(

recursive mutex ),也就是,當前持有某令牌的線程可以多次重新獲取它,而不會阻塞。而且,當令牌被釋放時,它確保下一個正阻塞並等待此令牌的線程就是下一個被放行的線程。

ACE_Null_Token

令牌接口的“無爲”(

do-nothing )實現,在你知道不會出現多個線程時使用。

ACE_Lock

定義鎖定接口的接口類。一個純虛類,如果使用的話,必須承受虛函數調用開銷。

ACE_Lock_Adapter

基於模板的適配器,允許將前面提到的任意一種鎖定機制適配到

ACE_Lock 接口。

 

4-1 ACE 鎖類屬中的類

 

4-1 中描述的類都支持同樣的接口。但是,在任何繼承層次中,這些類都是互不關聯 的。在 ACE 中,鎖通常用模板來參數化,因爲,在大多數情況下,使用虛函數調用的開銷都是不可接受的。使用模板使得程序員可獲得相當程度的靈活性。他可以在編譯時(但不是在運行時)選擇他想要使用的的鎖定機制的類型。然而,在某些情形中,程序員仍可能需要使用動態綁定和替換( substitution );對於這些情況, ACE 提供了 ACE_Lock ACE_Lock_Adapter 類。

 

4.2.1.1

使用互斥體類

  互斥體實現了“互相排斥 ”(

  任何線程在進入臨界區之前,必須獲取

  什麼時候需要使用互斥體呢?互斥體用於保護共享的易變代碼,也就是,全局或靜態數據。這樣的數據必須通過互斥體進行保護,以防止它們在多個線程同時訪問時損壞。

  下面的例子演示

mutual exclusion )同步的簡單形式(所以名爲互斥體 (mutex) )。互斥體禁止多個線程同時進入受保護的代碼“臨界區 ”( critical section )。因此,在任意時刻,只有一個線程被允許進入這樣的代碼保護區。 acquire )與此區域相關聯的互斥體的所有權。如果已有另一線程擁有了臨界區的互斥體,其他線程就不能再進入其中。這些線程必須等待,直到當前的屬主線程釋放 release )該互斥體。 ACE_Thread_Mutex 類的使用。注意在此處很容易用 ACE_Mutex 替換 ACE_Thread_Mutex 類,因爲它們擁有同樣的接口。

 

4-2

#include "ace/Synch.h"

#include "ace/Thread.h"

 

//Arguments that are to be passed to the worker thread are passed

//through this struct.

struct Args

{

public:

Args(int iterations): mutex_(),iterations_(iterations){}

ACE_Thread_Mutex mutex_;

int iterations_;

};

 

//The starting point for the worker threads

static void* worker(void*arguments)

{

Args *arg= (Args*) arguments;

for(int i=0;i<arg->iterations_;i++)

{

ACE_DEBUG((LM_DEBUG,

"(%t) Trying to get a hold of this iteration/n"));

 

//This is our critical section

arg->mutex_.acquire();

ACE_DEBUG((LM_DEBUG,"(%t) This is iteration number %d/n",i));

ACE_OS::sleep(2);

 

//simulate critical work

arg->mutex_.release();

}

 

return 0;

}

 

int main(int argc, char*argv[])

{

if(argc<2)

{

ACE_OS::printf("Usage: %s <number_of_threads>

<number_of_iterations>/n", argv[0]);

ACE_OS::exit(1);

}

 

Args arg(ACE_OS::atoi(argv[2]));

 

//Setup the arguments

int n_threads = ACE_OS::atoi(argv[1]);

 

//determine the number of threads to be spawned.

ACE_thread_t *threadID = new ACE_thread_t[n_threads+1];

ACE_hthread_t *threadHandles = new ACE_hthread_t[n_threads+1];

if(ACE_Thread::spawn_n(threadID, //id’s for each of the threads

n_threads, //number of threads to spawn

(ACE_THR_FUNC)worker, //entry point for new thread

0, //args to worker

THR_JOINABLE | THR_NEW_LWP, //flags

ACE_DEFAULT_THREAD_PRIORITY,

0, 0, threadHandles)==-1)

ACE_DEBUG((LM_DEBUG,"Error in spawning thread/n"));

 

//spawn n_threads

for(int i=0; i<n_threads; i++)

ACE_Thread::join(threadHandles[i]);

 

//Wait for all the threads to exit before you let the main fall through

//and have the process exit.

return 0;

}

 

在上面的例子中,

  在此例中,一開始,每個線程立即進入

ACE_Thread 包裝類用於生成多個線程來執行 worker() 函數,就如同在前面的例子裏一樣。 Arg 對象作爲參數傳入各個線程,在該對象中含有循環要執行的次數,以及將要使用的互斥體。 for 循環。一進入循環,線程就進入了臨界區。在臨界區內完成的工作使用 ACE_Thread_Mutex 互斥體對象進行保護。該對象由主線程作爲參數傳給工作者線程。臨界區控制是通過在 ACE_Thread_Mutex 對象上發出 acquire() 調用,從而獲取互斥體的所有權來完成的。一旦互斥體被獲取,沒有其他線程能夠再進入這一代碼區。臨界區控制是通過使用 release() 調用來釋放的。一旦互斥體的所有權被放棄,就會喚醒所有其他在等待的線程。這些線程隨即相互競爭,以獲得互斥體的所有權。第一個試圖獲取所有權的線程會進入臨界區。

 

4.2.1.2

將鎖和鎖適配器 Lock Adapter )用於動態綁定

  如前面所提到的,各種互斥體鎖應被直接用於你的代碼,或者,如果需要靈活性,作爲模板參數來使用。但是,如果你需要動態地(也就是在運行時)改變你的代碼所用鎖的類型,就無法使用這些鎖。

  爲應對這個問題,

  下面的例子演示

ACE 擁有 ACE_Lock ACE_Lock_Adapter 類,它們可用於這樣的運行時替換( substitution )。 ACE_Lock 類和 ACE_Lock_Adapter 怎樣爲應用程序員提供方便,和鎖定機制一起使用動態綁定和替換。

 

4-3

#include "ace/Synch.h"

#include "ace/Thread.h"

 

//Arguments that are to be passed to the worker thread are passed

//through this class.

struct Args

{

public:

Args(ACE_Lock* lock,int iterations):

mutex_(lock),iterations_(iterations){}

ACE_Lock* mutex_;

int iterations_;

};

 

//The starting point for the worker threads

static void* worker(void*arguments)

{

Args *arg= (Args*) arguments;

for(int i=0;i<arg->iterations_;i++)

{

ACE_DEBUG((LM_DEBUG,

"(%t) Trying to get a hold of this iteration/n"));

 

//This is our critical section

arg->mutex_->acquire();

ACE_DEBUG((LM_DEBUG,"(%t) This is iteration number %d/n",i));

ACE_OS::sleep(2);

 

//simulate critical work

arg->mutex_->release();

}

 

return 0;

}

 

int main(int argc, char*argv[])

{

if(argc<4)

{

ACE_OS::printf("Usage: %s <number_of_threads>

<number_of_iterations> <lock_type>/n", argv[0]);

ACE_OS::exit(1);

}

 

//Polymorphic lock that will be used by the application

ACE_Lock *lock;

 

//Decide which lock you want to use at run time,

//recursive or non-recursive.

if(ACE_OS::strcmp(argv[3],"Recursive"))

lock=new ACE_Lock_Adapter<ACE_Recursive_Thread_Mutex>;

else

lock=new ACE_Lock_Adapter<ACE_Thread_Mutex>

 

//Setup the arguments

Args arg(lock,ACE_OS::atoi(argv[2]));

 

//spawn threads and wait as in previous examples..

}

 

在此例中,和前面的例子唯一的不同是

ACE_Lock 類是和 ACE_Lock_Adapter 一起使用的,以便能提供動態綁定。底層的鎖定機制使用遞歸還是非遞歸互斥體,是在程序運行時由命令行參數決定的。使用動態綁定的好處是實際的鎖定機制可以在運行時被替換。缺點是現在對鎖的每次調用都需要負擔額外的經由虛函數表的間接層次。

 

4.2.1.3

使用令牌( Token

  如表

  遞歸鎖允許同一線程多次獲取同一個鎖。線程不會因爲試圖獲取它已經擁有的鎖而死鎖。這些類型的鎖能在各種不同 的情況下派上用場。例如,如果你用一個鎖來維護跟蹤流的一致性,你可能希望這個鎖是遞歸的,因爲某個方法可以調用一個跟蹤例程,獲取鎖,被信號中斷,然後 再嘗試獲取這個跟蹤鎖。如果鎖是非遞歸的,線程將會在這裏鎖住它自己。你會發現很多其他需要遞歸鎖的有趣應用。重要的是要記住,你獲取遞歸鎖多少次,就必須釋放 它多少次。

  在

  儘管

4-1 中所提到的, ACE_Token 類提供所謂的“遞歸互斥體”,它可以被最初獲得它的同一線程進行多次重新獲取。 ACE_Token 類還確保所有試圖獲取它的線程按嚴格的 FIFO (先進先出)順序排序。 SunOS 5.x 上運行例 4-3 ,釋放鎖的線程常常也是重新獲得它的線程(大約 90% 的情況是這樣)。但是如果你採用 ACE_Token 類作爲鎖定機制來運行這個例子,每個線程都會輪流獲得令牌,然後有序地把機會讓給下一個線程。 ACE_Token 作爲所謂的遞歸鎖非常有用,它們實際上是更大的“令牌管理”構架的一部分。該構架允許你維護數據存儲中數據的一致性。遺憾的是,這已經超出了此教程的範圍。

 

4-4

#include "ace/Token.h"

#include "ace/Thread.h"

 

//Arguments that are to be passed to the worker thread are passed

//through this struct.

struct Args

{

public:

Args(int iterations):

token_(“myToken”),iterations_(iterations){}

ACE_Token token_;

int iterations_;

};

 

//The starting point for the worker threads

static void* worker(void*arguments)

{

Args *arg= (Args*) arguments;

for(int i=0;i<arg->iterations_;i++)

{

ACE_DEBUG((LM_DEBUG,"(%t) Trying to get a hold of this iteration/n"));

 

//This is our critical section

arg->token_.acquire();

ACE_DEBUG((LM_DEBUG,"(%t) This is iteration number %d/n",i));

 

//work

ACE_OS::sleep(2);

arg->token_.release();

}

 

return 0;

}

 

int main(int argc, char*argv[])

{

//same as previous examples..

}

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