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"));
}