Обновите shared_lock до уникального использования блокировки, времени и дизайна - PullRequest
1 голос
/ 13 января 2020

Я обновляю код, который ранее использовал собственный механизм блокировки чтения и записи (этот код был написан до C ++ 11, а std :: shared_mutex еще не существует), чтобы использовать стандартную версию C ++.

Существует два класса с именами ReadLock и WriteLock, и ReadLock можно обновить до WriteLock с помощью вызова метода. WriteLock также можно получить в любое время без обновления с shared_lock. Читая стандартную версию shared_lock на C ++, я думаю, что она проста и проста.

ReadLock будет просто заменен на shared_lock. WriteLock будет заменен на unique_lock и может быть запущен в любое время, вызывая lock (), чтобы получить обновление Writelock до Записывающая блокировка будет выполняться в два этапа: разблокировка shared_lock и блокировка unique_lock

Теперь моя проблема в том, что когда я читаю обсуждения, могут возникнуть определенные c проблемы, и подобная тема вызвала беспокойство (тема из Говарда Хиннанта ) Может ли общая блокировка на std :: shared_timed_mutex быть обновлена ​​до эксклюзивной блокировки?

Поэтому я рекомендую вместо этого использовать версию boost, поскольку она поддерживает upgrade_lock и boost :: upgrade_to_unique_lock, но я Я не совсем понимаю, как подходить к дизайну.

Класс WriteLock может представлять объекты unique_lock и / или upgrade_lock и upgrade_to_unique_lock, поскольку, как я уже упоминал выше, WriteLock может быть достигнут и без shared_lock.

* 101 4 * Кроме того, я не совсем понимаю, как явно запускать механизмы lock () и unlock (), если я использую upgrade_lock из boost; Boost :: upgrade_lock имеет конструктор, который принимает defer_lock в качестве параметра и имеет методы lock () и unlock (), которые я могу использовать в любое время, но я не вижу той же функции, если мы обновим ее до уникальной блокировки с помощью boost :: upgrade_to_unique_lock () , создание объекта upgrade_to_unique_lock () автоматически преобразует и блокирует его.

Вот псевдокод того, что я пытаюсь достичь, подход 1, базовый c, операция

    void foo()
    {
        ReadLock readLock = someWrapper->AcquireReader();    // return a shared lock
        ...
        WriteLock writeLock = readLock->UpgradeToWriter();   // returns a unique lock
        writeLock->Lock();
        // do something here
    }   // writelock are unlock since constructor is called

, подход 2 прямой up writelock

    void foo()
    {
        WriteLock writeLock = someWrapper->GetWriter();   // acquire lock straight
        writeLock->Lock();
        // do something here
    }   // writelock are unlock since constructor is called
}

так что мои вопросы здесь

  1. Является ли мое беспокойство, если я использую стандартный C ++ допустимым, что мне нужно вместо этого использовать boost или достаточно C ++ std :: shared_mutex ? В приведенном выше примере и UpgradeToWriter (), и GetWriter () просто вернут объект с unique_lock, но Upgrade сначала просто разблокирует shared_lock.
  2. Если я использую версию Boost, как мне подходить к дизайну, так как upgrade_to_unique_lock другой тип для unique_lock? Я думал, что класс WriteLock содержит определения unique_lock, upgrade_lock и boost: upgrade_to_unique_lock и будет заблокирован, будь то обновление или просто получение, которое подводит меня к моему последнему и последнему вопросу
  3. Как явно или заблокирован / блокировка триггера для повышения: upgrade_to_unique_lock? так как он не имеет ни параметра defer_lock, ни метода lock () и unlock (), а только конструктор, который делает свое дело?

из примера повышения при использовании boost :: upgrade_to_unique_lock, все примеры выглядят Как и в приведенном ниже коде, создание объекта автоматически вызывает преобразование и блокировку.

void writer()
{
  // get upgradable access
  boost::upgrade_lock<boost::shared_mutex> lock(_access);

  // get exclusive access
  boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock); // <-- want this to be performed or triggered explicitly, how?
  // now we have exclusive access
}

Заранее спасибо, я знаю, что здесь есть эксперты по C ++, которые могут помочь брату

1 Ответ

2 голосов
/ 13 января 2020

Вот что вам не хватает:

  1. Каждый из двух потоков имеет обновляемую блокировку чтения.
  2. Оба потока пытаются обновить свою блокировку чтения до блокировки записи.
  3. Ни один поток не может продвигаться вперед, пока не будут сняты все другие блокировки чтения.
  4. Оба потока удерживают блокировку чтения.

Это тупик. Таким образом, у вас есть два варианта:

  1. Убедитесь, что такая ситуация никогда не произойдет: только один поток может удерживать обновляемую блокировку чтения одновременно.
  2. Устранить тупик: при попытке обновить блокировка чтения может привести к сбою операции и потребовать, чтобы поток снял блокировку чтения, прежде чем попытаться получить блокировку записи.
...