Как сделать сравнение и увеличить атомарно?
В моей попытке разработать поточно-безопасный класс шаблонов слабых указателей С++ мне нужно проверить флаг, указывающий на то, что объект все еще жив, если да, то увеличивайте счетчик ссылок на объекты, и мне нужно выполнить оба действия атомарно.
Я знаю существование функций intrinsics, предоставляемых компилятором, например _InterlockedCompareExchange() и _InterlockedIncrement(). Но то, что я хочу, является функцией interlockedCompareIncrement(), существует ли эффективный способ имитации этого внутреннего использования с использованием других примитивов, по крайней мере на платформе Windows x86?
Ответы
Ответ 1
Предположим, что value
- ваша переменная флага. Он должен быть объявлен volatile
.
long curvalue;
long newvalue;
do
{
curvalue = value;
newvalue = curvalue + 1;
}
while( _InterlockedCompareExchange( &value, newvalue, curvalue ) != curvalue );
Как вы видите, вы можете обобщить это на любую арифметику, которая вам нужна, изменив операции, которые применяются для вычисления newvalue
.
Если вы хотите сравнить два значения одновременно, лучше всего упаковать оба значения в одну переменную, а затем работать с этой единственной переменной. Поскольку вы используете флаг в сочетании с подсчетом ссылок, я бы рекомендовал использовать младший бит value
как флаг "живой", а затем увеличивать/уменьшать на 2 за раз. Это позволяет кодировать как флаг, так и счетчик ссылок в одну 32-битную переменную.
Ответ 2
Если вы хотите, чтобы ваша библиотека работала на нескольких процессорах или на нескольких основных машинах, вам необходимо использовать аппаратную поддержку, предоставляемую процессором. Вот несколько ссылок для вас:
http://en.wikipedia.org/wiki/Test-and-set
http://software.intel.com/en-us/forums/showthread.php?t=47498
Или вам нужно использовать механизм блокировки, предоставляемый ОС. Например,
http://msdn.microsoft.com/en-us/library/ms684841%28VS.85%29.aspx
или
http://en.wikipedia.org/wiki/POSIX_Threads
Ответ 3
Поскольку вы находитесь на С++, вы можете написать свой собственный ассемблерный код.
Возможно, это связано с Реализовать атомный приращение с использованием атомного свопа?