我正在寻找一种在C ++中使用 pthread rwlock 结构和条件例程的方法。
我有两个问题:
第一:如何可能,如果我们不能,为什么?
第二:为什么当前的POSIX pthread没有实现这种行为?
为了理解我的目的,我解释了我的用途:我有一个处理一个共享数组的生产者 - 消费者模型。消费者将在数组为空时cond_wait,但在读取某些元素时将使用rdlock。当添加(+信号)或从数组中删除elems时,生产者将扭曲。
使用rdlock而不是mutex_lock的好处是提高性能:当使用mutex_lock时,几个读取器会阻塞,而使用rdlock时,几个读取器不会阻塞。
答案 0 :(得分:6)
我认为“条件”是指“条件变量”。他们是不同的东西。
不,在等待条件变量时不能使用rwlock。我不能回答“为什么”,但这就是POSIX决定这样做的方式。也许只是为了让事情变得简单。
但是,您仍然可以通过在不使用POSIX rwlock的情况下仅使用互斥锁和2个条件变量来创建自己的rwlock类来获得所需的行为:
getReadLock():
lock(mutex)
while(array.empty())
wait(readersCondVar, mutex)
readers++;
unlock(mutex)
releaseReadLock():
lock(mutex)
if (--readers == 0)
broadcast(writerCondVar, mutex) // or signal, if only 1 producer
unlock(mutex)
readerThread:
forever() {
getReadLock()
read()
releaseReadLock()
}
getWriteLock():
lock(mutex)
while(readers) {
wait(writerCondVar, mutex)
}
releaseWriteLock():
broadcast(readersCondVar, mutex)
unlock(mutex)
writerThread():
forever() {
getWriteLock()
write()
releaseWriteLock()
}
简单并做你想做的事。
答案 1 :(得分:1)
C ++ 0x正在获得多线程支持,并且该支持包括一个名为condition_variable_any的新类型:
class condition_variable_any
{
public:
condition_variable_any();
~condition_variable_any();
condition_variable_any(const condition_variable_any&) = delete;
condition_variable_any& operator=(const condition_variable_any&) = delete;
void notify_one();
void notify_all();
template <class Lock>
void wait(Lock& lock);
template <class Lock, class Predicate>
void wait(Lock& lock, Predicate pred);
template <class Lock, class Clock, class Duration>
cv_status
wait_until(Lock& lock,
const chrono::time_point<Clock, Duration>& abs_time);
template <class Lock, class Clock, class Duration, class Predicate>
bool
wait_until(Lock& lock,
const chrono::time_point<Clock, Duration>& abs_time,
Predicate pred);
template <class Lock, class Rep, class Period>
cv_status
wait_for(Lock& lock,
const chrono::duration<Rep, Period>& rel_time);
template <class Lock, class Rep, class Period, class Predicate>
bool
wait_for(Lock& lock,
const chrono::duration<Rep, Period>& rel_time,
Predicate pred);
};
这里有一个如何实现condition_variable_any的解释:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html#gen_cond_var
但是在这个链接上它被命名为gen_cond_var。 condition_variable_any的神奇之处在于它将等待任何具有lock()和unlock()成员的东西。一旦你有condition_variable_any,那么你需要的只是一个rwlock。上面的链接还介绍了shared_mutex和shared_lock,并显示了您想要的示例代码:
std::tr2::shared_mutex mut;
std::gen_cond_var cv;
void wait_in_shared_ownership_mode()
{
std::tr2::shared_lock<std::tr2::shared_mutex> shared_lk(mut);
// mut is now shared-locked
// ...
while (not_ready_to_proceed())
cv.wait(shared_lk); // shared-lock released while waiting
// mut is now shared-locked
// ...
} // mut is now unlocked
void wait_in_unique_ownership_mode()
{
std::unique_lock<std::tr2::shared_mutex> lk(mut);
// mut is now unique-locked
// ...
while (not_ready_to_proceed())
cv.wait(lk); // unique-lock released while waiting
// mut is now unique-locked
// ...
} // mut is now unlocked
上述文件有点过时了。这里有一个更新的shared_mutex / shared_lock实现和描述:
http://howardhinnant.github.io/shared_mutex http://howardhinnant.github.io/shared_mutex.cpp
所有这些都是在POSIX pthreads之上实现的。我希望将共享锁定的东西放到C ++技术报告(tr2)中,但当然不能保证这一点。
答案 2 :(得分:1)
我有你需要的相同要求。
这是我的解决方案:
class rwlock
{
public:
rwlock()
{
pthread_rwlock_init(&_lock, nullptr);
}
~rwlock()
{
pthread_rwlock_destroy(&_lock);
}
void read_lock()
{
pthread_rwlock_rdlock(&_lock);
}
void write_lock()
{
pthread_rwlock_wrlock(&_lock);
}
bool try_read_lock()
{
return pthread_rwlock_tryrdlock(&_lock) == 0;
}
bool try_write_lock()
{
return pthread_rwlock_trywrlock(&_lock) == 0;
}
void lock()
{
read_lock();
}
void try_lock()
{
try_read_lock();
}
void unlock()
{
pthread_rwlock_unlock(&_lock);
}
private:
pthread_rwlock_t _lock;
};
rwlock lock;
std::condition_variable_any cond;
bool ready = false;
lock.write_lock();
...
if (!ready) {
ready = true;
cond.notify_all();
}
lock.unlock();
std::unique_lock<rwlock> lock_(lock);
while (!ready) {
cond.wait(lock_, []{ return ready; });
}
...
ready = false;
答案 3 :(得分:0)
对于你想要的,你需要只有一组rwlock和一组互斥/ cond变量,伪代码(虽然你需要在posix cond变量上通常的循环)
consumer() {
get_readlock();
if(array_empty()) {
release_readlock();
grab_mutex();
wait_on_condition();
release_mutex();
get_readlock();
}
process_elements();
release_readlock();
}
producer()
{
get_writelock();
get_mutex();
insert_elements();
signal_condition();
release_mutex();
release_writelock();
}
我猜测条件变量只适用于互斥锁,因为等待或发信号通知条件需要相互排斥。
答案 4 :(得分:0)
要解决世界末日发出的问题,必须在grab_mutex
之后和wait_on_condition
之前再次检查条件:
consumer() {
get_readlock();
if(array_empty()) {
release_readlock();
grab_mutex();
if(array_empty()) {
wait_on_condition();
}
release_mutex();
get_readlock();
}
process_elements();
release_readlock();
}
答案 5 :(得分:0)
在互斥锁和condvars之上实现了几个RWLocks。选择任何一个并添加一些condvars以满足您的自定义需求。