Boost upgrade_lock и DCLP (дважды проверенная схема блокировки)

Предположим, у нас есть следующий (псевдо) код:

using UpgradeLock = boost::upgrade_lock<boost::shared_mutex>;
using UpgradeToUniqueLock = boost::upgrade_to_unique_lock<boost::shared_mutex>;

boost::shared_mutex mtx;

void DeleteTable(<tbl>) {
UpgradeLock lock(mtx);
if (<the table exists>) {
UpgradeToUniqueLock up(lock); // (!)
// delete the table
}
}

И предположим, что два потока только что вошли в эту функцию и оба достигли утверждения, помеченного (!),

Я не могу понять, что будет потом. У меня есть следующие варианты:

  1. Один поток не может получить эксклюзивный доступ, пока второй не освободит свой UpgradeLock, но не может, пока не получит эксклюзивный доступ тоже. Тупик.
  2. Один поток получает эксклюзивный доступ, в то время как другой находится на линии с отметкой (!),

Я предполагаю, что второй вариант — это то, что, вероятно, произойдет, но в этом случае выясняется, что, даже заблокировав среду, мы должны перепроверить, что наши данные не были изменены «снаружи», то есть мы должны использовать пресловутый DCLP. Я прав?

Я не нашел правдоподобной информации об этом, так что не вините меня много 🙂

2

Решение

Если я правильно вас понимаю, тогда число 2 произойдет.

Если вы используете Замки для чтения / записи Вы должны придерживаться протокола, который предполагает, что, пока несколько читателей разделяют блокировку, им разрешен только доступ на чтение. Если им нужно получить некоторые права на запись, они должны обновить блокировку.

Теперь в вашем случае может случиться так, что несколько потоков входят в if-установление и ожидание получения блокировки. Это правда, и все они получат блокировку один за другим. Проблема в том, что сразу после получения блокировки может случиться так, что другой поток уже deleteна столе.

Вот почему вам может понадобиться дважды проверенная схема блокировки.

Отсюда у вас есть несколько вариантов:

Опция 1:
проверьте, указывает ли таблица на NULL и ничего не делать

вариант 2:
просто позвони delete опять же, если указатель установлен в NULL или же nullptr после звонка delete C ++ хорошо с этим (если delete исходит из стандартной библиотеки lib) => и просто ничего не будет делать. Просто для справки читайте:

http://en.cppreference.com/w/cpp/language/delete

если выражение имеет нулевое значение указателя, деструкторы не вызываются, а функция освобождения не вызывается.

  UpgradeLock lock(mtx);

if (<the table exists>)
{
UpgradeToUniqueLock up(lock); // (!)
if(<table still exists>)
{
// delete the table
// and set the pointer to nullptr
}
}

но в соответствии с вариантом 2 следующий фрагмент будет просто, если delete реализуется STL:
Блокировка UpgradeLock (MTX);

  if (<the table exists>)
{
UpgradeToUniqueLock up(lock); // (!)
// delete the table
// and set the pointer to nullptr

}

вариант 3:
использование std::shared_ptr или же boost::shared_ptr вместо. Они синхронизированы. Так что вам даже не нужны замки, просто позвоните ptr.reset() из нескольких потоков и все.

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]