C ++ 11 блокирует бесплатное обновление 2 переменных атомарно

Я хотел бы обновить atomicX когда поток находит новый минимум, чтобы изменить его на. Когда он устанавливает новый минимум, я также хотел бы изменить переменную yатомно. Есть ли способ сделать это без замков?

Пример функции потока, выполняющейся одновременно на нескольких потоках:

uint64_t x = atomicX;
int y = g();

for(int newX = 0; newX < x; ++newX)
{
if(f(newX))
{
while(newX < x && !atomicX.compare_exchange_strong(x, newX));
// also set atomicY to y if the exchange happened above
break;
}

x = atomicX;
}

Я могу сделать это с замками так:

int y = g();

for(uint64_t newX = 0; newX < atomicX; ++newX)
{
if(f(newX))
{
mutex.lock();
if(newX < atomicX)
{
atomicX = newX;
atomicY = y; // atomicY no longer needs to be atomic
}
mutex.unlock()
break;
}
}

Я также открыт для любого более чистого структурирования этого или другого способа сделать все это вместе. Мне не нравится, что у меня должно быть то же самое newX < x условие дважды, или что я должен разорвать петлю.

4

Решение

Существует довольно простое и достаточно портативное решение, которое заключается в использовании указателя и CAS, которые:

struct XY {
uint64_t x;
uint32_t y;
};
std::atomic<XY *> globalXY;

Затем становится сложнее понять, как распределять и освобождать эти объекты без чрезмерных затрат или проблем с ABA.

Для ясности код в конечном итоге будет выглядеть примерно так:

XY *newXY = somehow_allocate_objects();
XY *oldXY = globalXY;
int oldX = oldXY->x;
newXY->y = g();

for(int newX = 0; newX < oldX; ++newX) {
if(f(newX)) {
// prepare newXY before swapping
newXY->x = newX;
while(newX < oldX && !globalXY.compare_exchange_strong(oldXY, newXY)) {
// oldXY was updated, reload oldX
oldX = oldXY->x;
}
// globalXY->x,y both updated by pointer CAS
break;
}
oldXY = globalXY;
oldX = oldXY->x;
}

Для справки, окончательный вывод состоял в том, что эти потоки были долгоживущими, поэтому статически выделяли один XY экземпляра для каждого потока было достаточно.

1

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


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