现在的位置: 首页 > 综合 > 正文

Ice笔记–C++线程与并发(小结)

2013年10月06日 ⁄ 综合 ⁄ 共 2853字 ⁄ 字号 评论关闭
文章目录

                                                             C++线程与并发(Ice3.4.2)

概述

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<Mutex> Lock;
        typedef TryLockT<Mutex>TryLock;

};

 

1.2)使用互斥类

假设有一个FileSystem类和write的函数如下:

#include<IceUtil/Mutex.h>

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类对象的析构函数,同时会解除互斥锁的加锁状态。

2.递归互斥体(The C++ RecMutex Class)

上面所介绍的互斥体是非递归性质的,也就是说他们不能被多次加锁,即使是已经拥有该所的线程也不行。这样会给一些情况带来不便

IceUtil::Mutex_mutex;

void f1()
{
      IceUtil::Mutex::Lock lock(_mutex);
      // ...
}

void f2()
{
    IceUtil::Mutex::Locklock(_mutex);
    f1();    // Deadlock!
    // ...
}

         为了解决这个问题,Ice同样也提供了递归互斥锁,如下示例:

#include <IceUtil/RecMutex.h>

IceUtil::RecMutex _mutex; // Recursive mutex

void f1()
{
       IceUtil::RecMutex::Lock lock(_mutex);   //如果该互斥体已被其他线程加锁,那么该线程将会被挂起
        // ...
}

void f2()
{
       IceUtil::RecMutex::Lock lock(_mutex);
       f1(); // Fine
       //...
}
  

3. 读写递归互斥体(The RWRecMutex Class)

由于递归互斥体无论是在读取还是写操作的情况下,都是将其并发线程访问序列化。但是读取资源的线程并不会修改所访问的内容;因此让多个读取线程并行拥有互斥体,而同一时刻只能有一个写入的线程获取互斥体。

下面是该读写互斥类的定义:

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 RLockT<RWRecMutex>RLock;
               typedefTryRLockT<RWRecMutex> TryRLock;
               typedef WLockT<RWRecMutex>WLock;
               typedefTryWLockT<RWRecMutex> TryWLock;
      };
}

4.定时锁

读写锁提供了一些可使用超时的成员函数。等待的时间量是通过IceUtil::Time类的实例指定的。

5.监控器(The Monitor)

     5.1 Monitor类定义

       Monitor类在IceUtil::Monitor中定义,如下所示:

     namespace IceUtil {
         template <class T>
         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<Monitor<T> > Lock;
                   typedefTryLockT<Monitor<T> > TryLock;
         };
}

 

    Monitor类相对于互斥体来说,它提供的互斥机制更为灵活,因为他们允许线程检查某一条件,如果条件为假,就让自己休眠;而这线程会让其他某个改变了条件状态的线程唤醒。

   关于如何使用该Monitor类,可以参考上一篇文章--C++线程与并发(二)。

 

抱歉!评论已关闭.