Как реализовать атомарный инкремент указателя на целое число, используя C ++ 11 & lt; atomic & gt ;?

При портировании некоторого кода Windows C ++ на iOS мне нужно предоставить реализацию Win32 long InterlockedIncrement(long *p) вызов. Это достаточно просто, используя функции, определенные в <libkern/OSAtomic.h>,

Тем не менее, мне интересно, можно ли написать это независимым от ОС способом, используя только средство C ++ 11, главным образом <atomic>, Я пришел с этим, что я не уверен, что выполняет то, что я хочу:

inline long InterlockedIncrement(long* p)
{
std::atomic<long&> atomicP(*p);
return ++atomicP;
}

Это работает? Это достаточно хорошо? Эти две строки не являются атомарными, но приращение должно быть атомарным, что является ключевым моментом здесь.

Все примеры использования для <atomic> что я нашел разные, где std::atomic<T> определяется и используется напрямую. Здесь я хочу использовать существующую длинную переменную, которую звонящие передают мне по адресу. Я не мог найти такой пример.

Редактировать: Clang 3.2 (в Xcode 4.x) не может скомпилировать ++atomicP с ошибкой «не может увеличить значение типа std::atomic<long&>«(ни atomicP += 1 или).

Какой будет правильный путь?

Отредактируйте снова: реализация указателя компилируется …

inline long InterlockedIncrement(long* p)
{
std::atomic<long*> atomicP(p);
return ++(*atomicP);
}

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

12

Решение

В вашем примере реализации каждый раз создается новый атом по указателю. Это не предполагаемое использование std :: atomic, и я не верю, что он работает так, как вам хотелось бы.

Насколько мне известно, единственный способ сделать то, что вы хотите сделать (удалить зависимость от InterlockedIncrement независимым от платформы способом), — это заменить все объявления для переменных, которые вы в настоящий момент вызываете вызовами «interlock» Win32, на std :: atomic version из них. Затем вы можете удалить заблокированные вызовы и использовать обычную семантику значений для атомного изменения переменной. Во всяком случае, это более читабельно (и в будущем будет легче поддерживать).

Я понимаю, что вы хотите оставить существующий (хорошо протестированный) код на месте, но я не думаю, что вы можете в вашем случае.

12

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

Я считаю, что вы могли бы использовать atomic_fetch_add операция. Посмотрите на пример Вот.

2

__atomic_add_fetch Расширение GCC

В GCC 4.8 стандартная библиотека C ++ реализует std::atomic::operator++ со встроенным GCC __atomic_add_fetchтак что вы могли бы написать:

inline long InterlockedIncrement(long* p)
{
return __atomic_add_fetch(p, 1, __ATOMIC_SEQ_CST);
}

Я не уверен в лязг, но, кажется, есть несколько вариантов, таких как __c11_atomic_fetch_add http://clang.llvm.org/docs/LanguageExtensions.html

Как уже упоминалось, аргумент p само по себе должно быть std::atomic Вам следует использовать только стандартные библиотечные методы: преобразование указателя в атомарный не помогает, потому что атомарный указатель действует только на указатель, а не на то, на что он указывает.

2