我注意到提升似乎不支持信号量。获得类似效果的最简单方法是什么?
答案 0 :(得分:21)
这是使用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_;
}
};
答案 1 :(得分:7)
您需要Boost Interprocess semaphore或Boost Thread synchronization原语。
Mutex/Lock和condition是基元,通常用于在单个进程的多个线程之间同步对共享资源的访问。有exclusive,readers-writer和recursive/reentrant类型的互斥锁。换句话说,互斥锁是一种独占锁。当您需要解锁互斥锁并等待对象更改时,条件用于实现原子性。当你开始等待条件时,它会解锁互斥锁并保证解锁+等待调用是原子的,没有其他线程可以修改这两个操作之间的资源。
另一种情况下,信号量是条件和互斥的混合,用于完全相同的目的,但同步跨进程的访问。
现在还有non-blocking/lock-free synchronization这样的事情变得非常受欢迎。当数据量相对较大且低延迟确实很重要时,我个人在高频交易应用程序中使用它。
在你的情况下,我假设5位哲学家可以在5个线程的单个过程中进行晚餐。在这种情况下,您必须使用互斥锁,而不是信号量。您可能会或可能不会使用条件。这取决于您想要实施该用餐程序的确切内容和准确程度。
我不知道如何更好地描述它,因为我最终会写一本关于它的书。所以我建议你找一些已经写好的书来理解基本概念。了解基础知识后,您可以使用POSIX threads,Boost Interprocess或Thread,ACE甚至non-blocking algorithms等API /库/框架来实现您的目标。
祝你好运!答案 2 :(得分:0)
我创建了一个与boost 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;
}
};