Использование переменной условия Pthread с rwlock
-
01-10-2019 - |
Вопрос
Я ищу способ использования pthread rwlock. структура с условия Процедуры в C ++.
У меня есть два вопроса:
Во-первых: как это возможно, и если мы не можем, почему?
Во-вторых: Почему нынешний POTREAD PHHREAD не реализовал это поведение?
Чтобы понять мою цели, я объясню, что будет мое использование: у меня есть модель потребительских производителей, занимающихся одним общим массивом. Потребитель будет COND_WAIT, когда массив пуст, но RDLock при чтении некоторых элементов. Производитель будет заблокироваться при добавлении (+ сигнал) или удаления утеплений из массива.
Преимущество использования RDLock вместо Mutex_Lock - улучшить производительность: при использовании Mutex_Lock, несколько читателей будут блокировать, тогда как использование RDLock несколько читателей не будет блокировать.
Решение
Я предполагаю, что по «условиям» вы имеете в виду «условные переменные». Они разные вещи.
Нет, вы не можете использовать RWlock, когда в ожидании условной переменной. Я не могу ответить на то, что «почему», но вот в том, что Posix решил сделать это. Возможно, просто держать вещи простыми.
Однако вы все еще можете получить желаемое поведение, сделав свой класс RWLOLS, используя только Mutex и 2 условные переменные без использования POSIX 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()
}
Просто и делает то, что вы хотите.
Другие советы
У меня такое же требование, как вам нужно.
Вот мое решение:
Wrap pthread_rwlock_t.
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;
C ++ 0x - получение многопотативной поддержки, и эта поддержка включает в себя новый тип под названием Condent_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);
};
Есть объяснение того, как реализовать условия_Variable_Any здесь:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html#gen_cond_var.
Но на этой связи названа Gen_cond_var. Волшебная вещь о условиях /variable_any заключается в том, что она будет ждать все, что имеет блокировку () и разблокировать () элементы. Как только у вас есть 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.
Все это реализовано на вершине phthreads posix. Я надеюсь получить общий замок в техническом отчете C ++ (TR2), но, конечно, нет никакой гарантии этого.
Для чего вы хотите, вам нужно просто иметь 1 набор RWLOLD и 1 набор переменной Mutex / COND, PSEUDO-кода (хотя вам понадобится обычные петли на переменных 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();
}
Я догадаю, что переменные состояния работают только с Mutexes, потому что ожидание или сигнализация условия нуждается в взаимной исключительности.
Есть несколько Rwlocks. реализован на вершине mutexes и конденсар. Выберите любого и добавьте некоторые конденсары для ваших пользовательских потребностей.
Чтобы решить проблему, сигнализируемую в течение дня, нужно проверить снова после 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();
}