Заборы памяти в подфункции против той же функции, что и изменение данных

Существуют ли различия в безопасности потоков, если я помещаю заборы памяти в подфункции, а не в функцию, в которой используются данные.
Нижний пример включает в себя обе версии. Интересно, есть ли различия, о которых я не знаю? Являются ли функции A_function а также B_function одинаково безопасен?

#include<atomic>

using std::atomic;
using std::atomic_thread_fence;
using std::memory_order_acquire;
using std::memory_order_release;

typedef struct
{
atomic<int> lock;
int counter;
}Data;

void A_acquire(atomic<int> * lock);
void A_release(atomic<int> * lock);
void A_function(Data * data);
void B_acquire(atomic<int> * lock);
void B_release(atomic<int> * lock);
void B_function(Data * data);

void A_acquire(atomic<int> * lock)
{
int ticket = lock->fetch_add(1);
while (0 != ticket)
{
lock->fetch_sub(1);
ticket = lock->fetch_add(1);
}
//DIFFERENCE HERE
}

void A_release(atomic<int> * lock)
{
//DIFFERENCE HERE
lock->fetch_sub(1);
}

void A_function(Data * data)
{
A_acquire(&data->lock);
atomic_thread_fence(std::memory_order_acquire); //DIFFERENCE HERE
data->counter += 1;
atomic_thread_fence(std::memory_order_release); //DIFFERENCE HERE
A_release(&data->lock);
}

void B_acquire(atomic<int> * lock)
{
int ticket = lock->fetch_add(1);
while (0 != ticket)
{
lock->fetch_sub(1);
ticket = lock->fetch_add(1);
}
atomic_thread_fence(std::memory_order_acquire); //DIFFERENCE HERE
}

void B_release(atomic<int> * lock)
{
atomic_thread_fence(std::memory_order_release); //DIFFERENCE HERE
lock->fetch_sub(1);
}

void B_function(Data * data)
{
B_acquire(&data->lock);
//DIFFERENCE HERE
data->counter += 1;
//DIFFERENCE HERE
B_release(&data->lock);
}

int main(void)
{
Data dat = { 0, 0 };
A_function(&dat);
B_function(&dat);
return 0;
}

0

Решение

Семантически нет никакой разницы между A_function а также B_function, Эффект ограждения памяти не ограничен телом функции.

Кроме того, как отмечает Фантом, ограждения памяти в вашем примере не нужны: оба fetch_sub() а также fetch_add() уже есть приобретать + релиз семантический.

Но с изменениями ниже, выборка релиза становится жизненно важной:

void A_acquire(atomic<int> * lock)
{
int ticket = lock->exchange(1);
while (0 != ticket)
{
ticket = lock->exchange(1);
}
//DIFFERENCE HERE
}

void A_release(atomic<int> * lock)
{
//DIFFERENCE HERE
lock->store(0, memory_order_relaxed);
}
2

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


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