代码之家  ›  专栏  ›  技术社区  ›  jonderry

如何在C++中使用Boost实现类似于信号量的东西?[复制品]

  •  8
  • jonderry  · 技术社区  · 14 年前

    这个问题已经有了答案:

    我注意到Boost似乎不支持信号量。达到类似效果的最简单方法是什么?

    3 回复  |  直到 6 年前
        1
  •  7
  •   login_not_failed yadhu    6 年前

    你要么需要 Boost Interprocess semaphore Boost Thread synchronization 基元。

    Mutex/Lock condition 是通常用于在单个进程的多个线程之间同步对共享资源的访问的原语。有 exclusive , readers-writer recursive/reentrant 互斥体的类型。换句话说,互斥锁是一个独占锁。条件用于在需要解锁互斥体并等待对象更改时实现原子性。当您开始等待某个条件时,它会解锁互斥体并保证unlock+call to wait是原子的,并且没有其他线程可以修改这两个操作之间的资源。

    在另一种情况下,信号量是条件和互斥的混合体,用于完全相同的目的,但用于同步进程间的访问。

    Mutex vs Semaphore .

    也有这样的事情 non-blocking/lock-free synchronization 这几天很流行。我个人在高频交易应用程序中使用它,当数据量相对较大且低延迟非常重要时。

    在你的例子中,我假设5个哲学家可以在一个进程中用5个线程来吃晚餐。在这种情况下,您必须使用互斥量,而不是信号量。不过,您可能使用条件,也可能不使用条件。这取决于你到底想实现什么,以及你到底想实现什么样的用餐过程。

    我不知道如何更好地描述它,因为我最终会写一本关于它的书。所以我建议你找一本已经写好的书来理解基本概念。一旦了解了基础知识,就可以使用API/库/框架,比如 POSIX threads , Boost Interprocess Thread , ACE 甚至 non-blocking algorithms 实现你想要的。

    祝你好运!

        2
  •  21
  •   Sander Cox    12 年前

    这是使用boost.thread实现非常简单的信号量的一种方法。它是一个线程间信号量,而不是进程间信号量。没有暗示的保证,等等。——我甚至还没有编译代码。它说明了互斥和条件变量是如何交互的,并假设了Boost的最新版本。

    注意互斥体和条件变量是如何“配对”的——线程必须拥有互斥体的锁才能等待条件变量,并在唤醒时重新获取锁。此外,更改数据的代码需要显式唤醒可能正在等待的其他代码。这意味着互斥量、条件变量、数据和导致唤醒的条件都是紧密耦合的。紧密耦合还意味着如果可能,数据、互斥和条件变量应该被封装——任何外部修改都可能以奇怪的方式破坏代码,包括死锁、错过的唤醒和其他奇怪的错误。

    所有这些都是对vlad lazarenko答案的补充——理解理论和原理至少和在多线程编程中使用“工作”代码一样重要。

    #include <boost/thread/condition_variable.hpp>
    #include <boost/thread/mutex.hpp>    
    #include <boost/thread/lock_types.hpp>
    
    
    class semaphore
    {
        //The current semaphore count.
        unsigned int count_;
    
        //mutex_ protects count_.
        //Any code that reads or writes the count_ data must hold a lock on
        //the mutex.
        boost::mutex mutex_;
    
        //Code that increments count_ must notify the condition variable.
        boost::condition_variable condition_;
    
    public:
        explicit semaphore(unsigned int initial_count) 
           : count_(initial_count),
             mutex_(), 
             condition_()
        {
        }
    
        unsigned int get_count() //for debugging/testing only
        {
            //The "lock" object locks the mutex when it's constructed,
            //and unlocks it when it's destroyed.
            boost::unique_lock<boost::mutex> lock(mutex_);
            return count_;
        }
    
        void signal() //called "release" in Java
        {
            boost::unique_lock<boost::mutex> lock(mutex_);
    
            ++count_;
    
            //Wake up any waiting threads. 
            //Always do this, even if count_ wasn't 0 on entry. 
            //Otherwise, we might not wake up enough waiting threads if we 
            //get a number of signal() calls in a row.
            condition_.notify_one(); 
        }
    
        void wait() //called "acquire" in Java
        {
            boost::unique_lock<boost::mutex> lock(mutex_);
            while (count_ == 0)
            {
                 condition_.wait(lock);
            }
            --count_;
        }
    
    };
    
        3
  •  0
  •   Vasilly.Prokopyev    9 年前

    我做了一个与boots兼容的信号量类 TimedLockable 概念,因此它可以与锁一起使用 boost::unique_lock<semaphore> . 它不是一个经典定义中的信号量,但可以作为一个信号量使用。尽管如此,希望它对某人有用。

    它经过了某种考验,但很可能我做错了什么。如果有人能证明它是正确的,那就太好了。

    class semaphore
    {
    private:
       semaphore(const semaphore & other);
       semaphore & operator = (const semaphore & other);
    
       boost::mutex _mutex;
       boost::condition_variable _condVar;
       size_t _count;
    
       class wait_predicate
       {
       private:
          const size_t & _countRef;
       public:
          wait_predicate(const size_t & countRef) : _countRef(countRef) {}
          bool operator()() { return _countRef > 0; }
       };
    
       // must be used inside a locked scope!
       inline wait_predicate getWaitPredicate() const 
       {
          return wait_predicate(_count);
       }
    
    public:
       semaphore(size_t size): _count(size)
       {}
    
       void lock()
       {
          boost::unique_lock<boost::mutex> local_lock(_mutex);
          _condVar.wait(local_lock, getWaitPredicate());
          _count--;
       }
    
       void unlock()
       {
          boost::unique_lock<boost::mutex> local_lock(_mutex);
          _count++;
          _condVar.notify_one();
       }
    
       bool try_lock()
       {
          boost::unique_lock<boost::mutex> local_lock(_mutex);
          if (0 == _count)
             return false;
    
          _count--;
          return true;
       }
    
       template <typename Duration>
       bool try_lock_for(const Duration & duration)
       {
          boost::unique_lock<boost::mutex> local_lock(_mutex);
          if (!_condVar.wait_for(local_lock, duration, getWaitPredicate()))
             return false;
    
          _count--;
          return true;
       }
    
       template <class TimePoint>
       bool try_lock_until(const TimePoint & timePoint)
       {
          boost::unique_lock<boost::mutex> local_lock(_mutex);
          if (!_condVar.wait_until(local_lock, timePoint, getWaitPredicate()))
             return false;
    
          _count--;
          return true;
       }
    
       template <class WaitCriteria>
       bool timed_lock(const WaitCriteria & criteria)
       {
          boost::unique_lock<boost::mutex> local_lock(_mutex);
          if (!_condVar.timed_wait(local_lock, criteria, getWaitPredicate()))
             return false;
    
          _count--;
          return true;
       }
    };