C++ (Qt)QAtomicInt state; void AcquireRead( void ){ while (true) { if (state >= 1024) { // старший бит взведен - данные недоступны DoNothing(); // холостой ход continue; // крутимся в while (рано или поздно др. нитка сбросит старший бит) } state.fetchAndAddAcquire(1); // атомарно увеличиваем счетчик (еще 1 нитка имеет доступ к данным) break; // доступ получен }}
C++ (Qt) if (state >= 1024) <---- здесь пороется собака state.fetchAndAddAcquire(1);
C++ (Qt)while(true) { int cachedstate = state.fetchAndStoreAcquire((int)state); // кэшируем значение глобальной переменной if (cachedstate < 1024 && state.testAndSetRelaxed(cachedstate, cachedstate)) { // проверяем не изменилось ли значение пока переходили на следующую инструкцию другим потоком и одновременно проверяем меньше ли оно 1024 state.fetchAndAddRelease(1); // увеличиваем счетчик на 1 и выходим из цикла break; }/*Если значение больше или не совпадает со значением в глобальной переменной, значит проиграли race-condition другому потоку и позволяем ему завершить начатое (то есть какой-то из потоков сейчас внутри блока if)*/ QThread::yieldCurrentThread(); // DoNothing() / continue}
C++ (Qt)while(true) { int cachedstate = state.fetchAndStoreAcquire((int)state); if (cachedstate >= 1024) QThread::yieldCurrentThread(); // DoNothing() / continue else if (state.testAndSetRelaxed(cachedstate, cachedstate)) { state.fetchAndAddRelease(1); break; }}
C++ (Qt) if (cachedstate < 1024 && state.testAndSetRelaxed(cachedstate, cachedstate)) // if вернул true но до того как следующая строка выполнится др. нитка может установить state = 1024 state.fetchAndAddRelease(1);
C++ (Qt)if (state.testAndSetRelaxed(cachedstate, cachedstate)) <-- здесь пороется собака state.fetchAndAddRelease(1);
C++ (Qt)while(true) { int cachedstate = state.fetchAndStoreAcquire((int)state); if (cachedstate >= 1024) QThread::yieldCurrentThread(); // DoNothing() / continue else if (state.testAndSetRelaxed(cachedstate, cachedstate+1)) break;}
C++ (Qt)void AcquireRead( QAtomicInt & state ){ while(true) { int cachedState = state; if (cachedState >= 1024) DoNothing(); else if (state.testAndSetAcquire(cachedState, cachedState + 1)) break; }}
state.fetchAndStoreAcquire((int)state)// псевдо-ассеблер :-)push [state]; // текущее значение state записывается в стек (более вероятно - в регистр)call [fetchAndStoreAcquire]; // перезапись
C++ (Qt)// предположим state 1023, пока мы его передавали в fetchAndStoreAcquire оно стало 1024int cachedstate = state.fetchAndStoreAcquire((int)state); // cachedstate стало 1024if (cachedstate >= 1024) // сработало условие (хотя не должно было), просто передали управление другому потоку, который продолжит цикл с прерванного места (возможно второй круг цикла или несколько лишних инструкций) // другой вариант. state 1024, пока мы его передавали в fetchAndStoreAcquire оно как-то поменялось на 1int cachedstate = state.fetchAndStoreAcquire((int)state); // cachedstate стало 1if (cachedstate >= 1024) // не срабатывает, уходим на else...else if (state.testAndSetRelaxed(cachedstate, cachedstate+1)) // и state и cachedstate равны 1, производим нужные действия.
C++ (Qt) while(true) { if (state >= 1024) DoNothing(); else if (state.testAndSetAcquire(state, state + 1)) break; }
C++ (Qt)// другой вариант. state 1024, пока мы его передавали в fetchAndStoreAcquire оно как-то поменялось на 1int cachedstate = state.fetchAndStoreAcquire((int)state); // cachedstate стало 1if (cachedstate >= 1024) // не срабатывает, уходим на else...else if (state.testAndSetRelaxed(cachedstate, cachedstate+1)) // и state и cachedstate равны 1, производим нужные действия.
C++ (Qt)while(true) { if (state >= 1024) DoNothing(); else if (state.testAndSetAcquire(state, state + 1)) break; }
C++ (Qt)volatile int& port = некий адрес в памяти, на который мэппиться устройство;int a = port; // получили первые 4 байтаint b = port; // получили следующие 4 байта... // и т.д. компилятор каждый раз лезет в память и ничего нигде не кеширует и не сохраняет при этом, так как при повторном чтении уже пользователем данные потеряются
C++ (Qt)void AcquireRead( QAtomicInt & state ){ while(true) { if (state >= 1024) DoNothing(); else { int result = state.fetchAndAddAcquire(1); // атомарно увеличиваем счетчик if (result >= 1024) // если старший бит успел проскочить до инкремента state.fetchAndAddAcquire(-1); // откат else break; // доступ получен } }}