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