随笔-167  评论-8  文章-0  trackbacks-0

锁类属包含的类包装简单的锁定机制,比如互斥体、信号量、读/写互斥体和令牌等。这里我就以互斥体为例简单的介绍一下其使用方法,对其它的锁类进行一些简单的说明。

1.互斥体的使用。

互斥体用于保护共享的易变代码,也就是全局或静态数据。这样的数据必须通过互斥体进行保护,以防止它们在多个线程同时访问时损坏。

在ACE中可以通过ACE_Thread_Mutex实现线程的访问互斥,下面的例子演示ACE_Thread_Mutex类的使用。

#include "ace/Thread.h" 
#include 
"ace/Synch.h" 

#include 
<iostream>
using namespace std;


ACE_Thread_Mutex mutex;

void* Thread1(void *arg) 
{
    mutex.acquire();
    ACE_OS::sleep(
3);
    cout
<<endl<<"hello thread1"<<endl;
    mutex.release();

    
return NULL; 
}
 

void* Thread2(void *arg) 
{
    mutex.acquire();
    cout
<<endl<<"hello thread2"<<endl;
    mutex.release();

    
return NULL; 
}
 

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

    ACE_Thread::spawn((ACE_THR_FUNC)Thread1);
    
    
//Thread2 比Thread1晚创建1秒钟,故后尝试获取互斥体
    ACE_OS::sleep(1);
    ACE_Thread::spawn((ACE_THR_FUNC)Thread2);
    
    
while(true)
        ACE_OS::sleep(
10);

    
return 0
}
 

ACE_Thread_Mutex主要有两个方法:

  1. acquire():用来获取互斥体,如果无法获取,将阻塞至获取到为止。
  2. release():用来释放互斥体,从而使自己或者其它线程能够获取互斥体。

当线程要访问共享资源时,首先调用acquire()方法获取互斥体,从而获取对改互斥体所保护的共享资源的唯一访问权限,访问结束时调用释放互斥体,使得其它线程能获取共享资源的访问权限。

在此例中,本来Thread2的打印消息在Thread1之前,但由于Thread1先获得互斥体,故Thread2只有待Thread1结束后才能进入临界区。读者朋友们可以通过将ACE_Thread_Mutex替换为ACE_NULL_Mutex看一下不加锁的执行结果。

2.ACE Lock类属简介。

ACE Lock类属列表如下:

名字

描述

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接口。

可以简单的分为以下几类:

  1. 互斥锁
    互斥锁(通常称为"互斥体"或"二元信号量")用于保护多线程控制并发访问的共享资源的完整性。互斥体通过定义临界区来序列化多线程控制的执行,在临界区中每一时刻只有一个线程在执行它的代码。互斥体简单而高效(时间和空间)。
    ACE线程库提供了Mutex式的类(是一组互斥体对象,拥有类似的接口),他是一种简单而高效的类型是"非递归"互斥体。非递归互斥体不允许当前拥有互斥体的线程在释放它之前重新获取它。否则,将会立即发生死锁。递归互斥体在ACE Recursive_Thread_Mutex类中可移植地实现。
  2. 读者/作者锁
    读者/作者锁与互斥体相类似。例如,获取读者/作者锁的线程也必须释放它。多个线程可同时获取一个读者/作者锁用于读,但只有一个线程可以获取该锁用于写。当互斥体保护的资源用于读远比用于写要频繁时,读者/作者互斥体有助于改善并发的执行。
    ACE线程库提供了一个叫作RW_Mutex的类,在C++封装类中可移植地实现了读者/作者锁的语义。读者/作者锁将优先选择权给作者。因而,如果有多个读者和一个作者在锁上等待,作者将会首先获取它。

计数信号量
在概念上,计数信号量是可以原子地增减的整数。如果线程试图减少一个值为零的信号量的值,它就会阻塞,直到另一个线程增加该信号量的值。
计数信号量用于追踪共享程序状态的变化。它们记录某种特定事件的发生。因为信号量维护状态,它们允许线程根据该状态来作决定,即使事件是发生在过去。
信号量比互斥体效率要低,但是,它们要更为通用,因为它们无需被最初获取它们的同一线程获取和释放。这使得它们能够用于异步的执行上下文中(比如信号处理器)。ACE线程库提供一个叫作Semaphore的类来可移植地在C++包装类中实现信号量语义。

posted on 2010-05-14 10:03 老马驿站 阅读(1075) 评论(0)  编辑 收藏 引用 所属分类: ACE