Следующий код представляет собой скелет класса атомарных указателей, взятый из приложения для имитации отжига в наборе тестов PARSEC для многопроцессорных систем с общей памятью< /а>.
В этом приложении центральной структурой данных является граф (точнее, список соединений интегральной схемы). Каждый узел в графе имеет атрибут, указывающий его физическое местоположение. Алгоритм порождает множество потоков, и каждый поток многократно и случайным образом выбирает два узла и меняет их физическое местоположение, если это приводит к лучшей стоимости маршрутизации для чипа.
Поскольку граф огромен и любая пара узлов может быть выбрана каждым потоком, единственное приемлемое решение — неблокируемая параллельная структура данных (CDS). Вот почему следующий класс AtomicPtr
имеет решающее значение (он используется для атомарного обмена указателями на два объекта физического местоположения без блокировок). Функция atomic_load_acq_ptr()
определена в ассемблере и близко соответствует std::atomic<T*>::load(memory_order_acquire)
.
Я хочу реализовать этот CDS, используя атомарность С++ 11.
template <typename T>
class AtomicPtr {
private:
typedef long unsigned int ATOMIC_TYPE;
T *p __attribute__ ((aligned (8)));
static const T *ATOMIC_NULL;
inline T *Get() const {
T *val;
do {
val = (T *)atomic_load_acq_ptr((ATOMIC_TYPE *)&p);
} while(val == ATOMIC_NULL);
return val;
}
inline void Swap(AtomicPtr<T> &X) {
// Define partial order in which to acquire elements to prevent deadlocks
AtomicPtr<T> *first;
AtomicPtr<T> *last;
// Always process elements from lower to higher memory addresses
if (this < &X) {
first = this;
last = &X;
} else {
first = &X;
last = this;
}
// Acquire and update elements in correct order
T *valFirst = first->Checkout(); // This sets p to ATOMIC_NULL so all Get() calls will spin.
T *valLast = last->PrivateSet(valFirst);
first->Checkin(valLast); // This restores p to valLast
}
};
Метод std::atomic<T*>::exchange()
можно использовать только для замены голого указателя T*
на объект std::atomic<T*>
. Как сделать обмен двумя объектами std::atomic<T*>
без блокировок?
Я могу предположить, что приведенный ниже класс AtomicPtr
сам может быть основан на std::atomic<T*>
, объявив:
std::atomic<T*> p;
и заменить все вызовы atomic_load_acq_ptr()
на std::atomic<T*>::load(memory_order_acquire)
и заменить все вызовы atomic_store_rel_ptr()
на std::atomic<T*>::store(memory_order_release)
. Но моей первой мыслью было, что std::atomic<T*>
должен заменить сам AtomicPtr
, и может быть умный способ напрямую обмениваться объектами std::atomic<T*>
. Какие-нибудь мысли?
std::atomic
в C++11. - person Casey   schedule 21.08.2013AtomicPtr
уже делает это, следуя дисциплине check-out\check-in: 1- Любой поток, который хочет выполнить обмен, сначала проверяет указатель (путем записи контрольного значения, называемогоATOMIC_NULL
выше), и, когда это делается, проверяет 2- Любой поток, который хочет прочитать (например, Get()) значение указателя, должен продолжать вращаться, если указатель был проверен. - person Ahmed Nassar   schedule 21.08.2013std::atomic<T*>
? - person Matthieu M.   schedule 21.08.2013