Атомное сравнение_exchange, но основано на установленном флаге, а не равенстве? - PullRequest
0 голосов
/ 28 января 2019

std :: atomic обеспечивает сравнение Compare_exchange_strong (a, b), если базовое значение в настоящее время равно "a", и если да, то заменяет его на "b" атомарным / потокобезопасным способом.

Существует ли какой-либо атомарный способ без блокировки выполнить аналогичную операцию, но вместо проверки на равенство с "b" он будет обрабатывать "b" как флаг и выполнять замену, если базовое значение имеет этот флаг?

Итак, в принципе, что-то вроде

bool compare_exchange_flags(std::atomic<int>& underlying, int& flag, int replacement)
{
  auto tmp = underlying.load();

  if((tmp & flag) == flag) // only perform replacement if flag is set
  {
    flag = tmp; // emulate compare_exchange_strong, where expected value is replaced with actual value
    underlying = replacement;
    return true;
  } else {
    flag = underlying.load();
    return false;
  }
}

только в версии, которая ... ну, на самом деле работает;) (приведенные выше операции совсем не атомарны, конечно)

Спасибо!


Для контекста: Это для шины сообщений.Эта шина имеет области памяти, связанные с некоторыми состояниями (такими как READABLE, WRITEABLE).

Каждое состояние должно быть улучшено с помощью некоторых флагов - например, состояние может быть просто «WRITEABLE», то есть средство записи может свободнозаписать данные во фрагмент (читатели в данный момент крутятся / заняты опросом).Или это может быть «WRITEABLE | SIGNALED», что подразумевает, что писатель может получить эту память для записи, но должен вызвать событие после записи данных, чтобы уведомить читателей.

Итак (ОЧЕНЬ концептуально это нене фактический код - просто для грубой демонстрации) что-то вроде

void send(...)
{
  auto expected = WRITEABLE;
  if(compare_exchange_flags(status, expected, WRITE_RESERVED))
  {
    // ... write data ...

    status = WRITTEN;

    if((expected & SIGNALED) = SIGNALED)
      wakeUpReaders();
  } else {
    tryAnotherRegion();
  }
}

1 Ответ

0 голосов
/ 28 января 2019

Нет такой инструкции.Но этот вид операций обычно выполняется с помощью цикла, который пытается обменять значение, пока значение имеет флаг:

bool replace_if_flag(std::atomic<int>& underlying, int flag, int replacement){

  auto tmp = underlying.load();

  if(!(tmp & flag)) return false;

  while (!underlying.compare_exchange_weak(tmp,replacement)){
    if(!(tmp & flag)) return false;
    }

  return true;
  }
...