Почему std :: atomic & lt; T & gt; :: compare_exchange_ * не должен страдать от проблемы ABA?

На некоторых форумах и в книгах (т.е. C ++ Параллелизм в действии) есть хороший пример многопользовательского / многопользовательского стека, и в поп Реализации они обычно делают следующее:


// head is an std::atomic<node*> variable
node *old_head = head.load();
while(old_head && !head.compare_exchange_weak(old_head, old_head->next));
...

Зачем использовать станд :: атомное<T>:: compare_exchange_ * предотвратить проблему ABA?
Скажем так:

  • old_head-> следующая получает решены до того, как поток будет прерван (непосредственно перед compare_exchange_weak)
  • тогда происходит сценарий БА
  • после возобновления потока голова == старая_глава является действительным; в этом случае old_head-> следующая не будет решены опять же, указывая на неверную ячейку памяти
  • compare_exchange_weak будет выполнен, пройдет, но значение old_head-> следующая все равно будет старый один

Тогда возникнет проблема, связанная с ABA.

Я верю, что что-то упустил. Что мне здесь не хватает?

ура

2

Решение

Да, вы бы страдали от проблемы с ABA здесь.

Хотя я думаю, что это не имеет значения, потому что реализация, на которую вы ссылаетесь (листинг 7.3 в CiA), в любом случае недопустима, это утечка узлов.

Если мы посмотрим на самую простую реализацию с подсчетом ссылок, используемую без блокировки std::shared_ptr(перечисляя 7.9 в CiA) мы видим, что проблема не возникнет. При использовании общих указателей old_head не будет удален, так как наш поток по-прежнему содержит ссылку на него, так как такой недавно созданный заголовок не может быть создан в адресе памяти старого заголовка.

Есть также ветка на официальном Параллелизм в действии Мэннинг форумов о проблемах ABA в реализации стека.

2

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

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

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