На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
Модераторы: Qraizer
  
> Реализация Read/Write мьютекса , Read/Write мьютекс с возможностью поднятия блокировки
    Предлагаю обсудить проблему поднятия уровня блокировки, с Read до Write, для соответствующих мьютексов, типа std::shared_mutex. Как известно, эта задача нерешаемая, но мне пришло в голову, что если при повышении защищаться не от блокировок вообще, а только от тех кто тоже пытается сделать upgrade, то уже будет неплохо. В остальных случаях можно сделать переблокировку и т.д.

    На скорую руку набросал вот такой код. Как обычно, прошу критики.

    ExpandedWrap disabled
      class CSharedMutex
      {
      public:
          typedef uint64_t TLockCounter;
          static const TLockCounter UpgradeMask = TLockCounter(1) << 63;
       
          //Блокировка на запись
          void lock() noexcept
          {
              m_mx.lock(); //Блокируем на запись
              while(m_cnt != 0) //Ждём того, кто сделал upgrade
                  std::this_thread::yield();
          }
       
          void unlock() noexcept
          {
              m_mx.unlock();
          }
       
          //Блокировка на чтение
          void lock_shared() noexcept
          {
              m_mx.lock();
              for (;;) //Ждём того, кто сделал upgrade
              {
                  TLockCounter cnt = m_cnt & ~UpgradeMask;
                  if (m_cnt.compare_exchange_weak(cnt, cnt + 1))
                      break;
              };
              m_mx.unlock();
          }
       
          void unlock_shared() noexcept
          {
              const TLockCounter cnt = m_cnt--;
       
              if (cnt & UpgradeMask)
              {
                  if (cnt == UpgradeMask) //Если была переблокировка при upgade, разблокируем запись
                  {
                      m_cnt = 0;
                      unlock();
                  }
                  else if ((cnt & ~UpgradeMask) == 1) //Если последний, сбрасываем флаг upgrade
                      m_cnt = 0;
              }
          }
       
          //Возвращает true, если был сделан upgrade, false - если переблокировка
          bool upgrade_lock() noexcept
          {
              for (;;)
              {
                  TLockCounter cnt = m_cnt;
                  if (cnt & UpgradeMask) //Если кто-то уже делает upgrade, переблокируем
                  {
                      unlock_shared();
                      lock();
                      m_cnt = UpgradeMask;
                      return false;
                  }
       
                  if (m_cnt.compare_exchange_weak(cnt, cnt | UpgradeMask))
                  {
                      //Если удалось установить флаг upgrade, ждём, когда выйдут все читатели
                      if (cnt != 1)
                          while (m_cnt != UpgradeMask + 1)
                              std::this_thread::yield();
       
                      break;
                  }
       
                  std::this_thread::yield();
              }
       
              return true;
          }
      protected:
          std::mutex m_mx;
          volatile std::atomic<TLockCounter> m_cnt;
       
      };
    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
    0 пользователей:


    Рейтинг@Mail.ru
    [ Script execution time: 0,0173 ]   [ 16 queries used ]   [ Generated: 20.04.24, 00:08 GMT ]