Ice服务器是多线程模型的。在涉及资源的访问和操作的时候将要考虑同步访问机制。
Ice线程库提供了一些与线程有关的抽象:
互斥体,递归互斥体,读写递归互斥体,监控器,一个线程抽象,允许开发者创建,控制,销毁线程。
1.互斥体(The Mutex Class) 1.1)互斥体的定义
IceUtil::Mutex类提供了简单的非递归互斥机制,其定义如下:
- namespaceIceUtil {
- enum MutexProtocol { PrioInherit, PrioNone };
- class Mutex {
- public:
- Mutex();
- Mutex(MutexProtocol p);
- ~Mutex();
- void lock() const; /*lock 函数尝试获取互斥体。如果互斥体已经锁住,它就会挂起发出调用的线程(calling thread),直到互斥体变得可用为止*/
- bool tryLock() const;/*trylock函数尝试获取互斥体。如果互斥体未被锁住则返回true,否则直接返回false*/
- void unlock() const; /*尝试解除互斥体的加锁*/
- typedef LockT Lock;
- typedef TryLockTTryLock;
- };
1.2)使用互斥类
假设有一个FileSystem类和write的函数如下:
- #include
- namespaceFilesystem {
- class FileI : virtual public File,
- virtual public Filesystem::NodeI {
- public:
- // ...
- private:
- Lines _lines;
- IceUtil::Mutex _fileMutex; //互斥锁
- };
- // ...
- }
- void Filesystem::FileI::write(const Filesystem::Lines &text,const Ice::Current &)
- {
- _fileMutex.lock();
- _lines = text;
- //if(somecondition)return ;
- _fileMutex.unlock();
- }
然而这种加入互斥机制的方法并不好,例如对互斥体加锁了但在函数返回时并没有实现解锁操作,这种情况下就引发死锁情况。
因此我们建议使用Ice提供的两个助手类Lock和TryLock,如下:
- voidSomeClass::someFunction(/* params here... */)
- {
- IceUtil::Mutex::Locklock(_mutex); // 对mutex对象加锁
- // Lots of complexcode here...
- if (someCondition) {
- return; // No problem
- }
- //...
- } // 此处调用Mutex类对象的析构函数,同时会解除互斥锁的加锁状态。
上面所介绍的互斥体是非递归性质的,也就是说他们不能被多次加锁,即使是已经拥有该所的线程也不行。这样会给一些情况带来不便
- IceUtil::Mutex_mutex;
- void f1()
- {
- IceUtil::Mutex::Lock lock(_mutex);
- // ...
- }
- void f2()
- {
- IceUtil::Mutex::Locklock(_mutex);
- f1(); // Deadlock!
- // ...
- }
为了解决这个问题,Ice同样也提供了递归互斥锁,如下示例:
- #include
- IceUtil::RecMutex _mutex; // Recursive mutex
- void f1()
- {
- IceUtil::RecMutex::Lock lock(_mutex); //如果该互斥体已被其他线程加锁,那么该线程将会被挂起
- // ...
- }
- void f2()
- {
- IceUtil::RecMutex::Lock lock(_mutex);
- f1(); // Fine
- //...
- }
由于递归互斥体无论是在读取还是写操作的情况下,都是将其并发线程访问序列化。但是读取资源的线程并不会修改所访问的内容;因此让多个读取线程并行拥有互斥体,而同一时刻只能有一个写入的线程获取互斥体。
下面是该读写互斥类的定义:
- namespaceIceUtil {
- class RWRecMutex {
- public:
- void readLock() const;
- bool tryReadLock() const;
- bool timedReadLock(const Time&) const;
- void writeLock() const;
- bool tryWriteLock() const;
- bool timedWriteLock(const Time&) const;
- void unlock() const;
- void upgrade() const;
- bool timedUpgrade(const Time&) const;
- typedef RLockTRLock;
- typedefTryRLockT TryRLock;
- typedef WLockTWLock;
- typedefTryWLockT TryWLock;
- };
- }
读写锁提供了一些可使用超时的成员函数。等待的时间量是通过IceUtil::Time类的实例指定的。
5.监控器(The Monitor)5.1 Monitor类定义
Monitor类在IceUtil::Monitor中定义,如下所示:
- namespace IceUtil {
- template
- class Monitor {
- public:
- void lock() const;
- void unlock() const;
- bool tryLock() const;
- void wait() const;
- bool timedWait(constTime&) const; //这个函数挂起调用它的线程,直到指定的时间流逝.如果在超时之前唤醒被挂起的线程,
- //这个调用就返回true;否则返回false。
- void notify();
- void notifyAll();
- typedefLockT Lock;
- typedefTryLockT TryLock;
- };
- }
Monitor类相对于互斥体来说,它提供的互斥机制更为灵活,因为他们允许线程检查某一条件,如果条件为假,就让自己休眠;而这线程会让其他某个改变了条件状态的线程唤醒。
关于如何使用该Monitor类,可以参考上一篇文章--C++线程与并发(二)。