#c #multithreading
#c #многопоточность #c
Вопрос:
У меня есть этот код на c (по сравнению с 2008):
LONGLONG res = InterlockedIncrement64(amp;m_longlong);
пробегая по нему, я хотел бы иметь возможность читать из той же переменной
LONGLONG res = InterlockedWHAT?64(amp;m_longlong)
Поскольку это 64-разрядная переменная, простое чтение не считается потокобезопасным, но я не могу найти правильный InterlockedXXX.
Как я должен прочитать эту переменную?
Комментарии:
1. в 64-битной архитектуре выровненное 64-битное чтение (QWORD) должно быть атомарным, IIRC. Посмотрите на tr1 / boost / c 0x atomic<int64_t> для переносимого решения без стресса
2. спасибо, но я предпочел бы не ссылаться на совершенно новую библиотеку прямо сейчас. ищу решение InterlockedXXX
3. идея комментария в том, что это НЕ ответ 🙂 Я просто излагал свои мысли. Если вы знаете арку, вы могли бы просто убедиться в правильности выравнивания и все готово. Вопрос недостаточно сформулирован, вот почему это не ответ.
4. @sehe: Вы не можете просто прочитать выровненную
QWORD
. Для обеспечения безопасности параллелизма вам нужны две вещи: атомарность и порядок записи / чтения. Даже если 64-разрядный процессор будет считывать значение атомарно, оптимизатор или центральный процессор могут неожиданным образом повлиять на чтение.
Ответ №1:
LONGLONG res = InterlockedCompareExchange64(amp;m_longlong, 0, 0);
Комментарии:
1. @user991339 — другой поток может изменять значение во время его чтения для ввода в стек в качестве второго параметра. Возвращаемое значение будет в порядке, но общая переменная тогда будет содержать мусор.
2.
InterlockedExchange64
не годится. Вам пришлось бы назвать это какInterlockedExchange64(amp;val, val)
, и теперь вы должны увидеть проблему. Как вы считываете значениеval
для передачи в качестве второго параметра? Это та же проблема, с которой вы начали.3. @Henrik — это может произойти и с InterlockedCompareExchange, когда m_longlong == 0 и 0 помещаются в стек, в то время как другой поток записывает какое-то другое значение, не так ли?
4. Нет, это невозможно. Если
m_longlong == 0
тогдаm_longlong
будет установлено значение 0 (т. Е. без изменений), или иным образомm_longlong
не будет изменено. Другими словами, код в этом ответе не может быть измененm_longlong
.5. Вы должны выбрать значение, которое
m_longlong
вряд ли будет иметь, чтобы избежать загрязнения строки кэша.
Ответ №2:
Вы можете использовать InterlockedOr64
и передать ноль в качестве второго параметра. Насколько я могу судить, это не является требованием Vista, предположительно, поскольку оно реализовано с помощью встроенных компиляторов.
Комментарии:
1. Обратите внимание, что это изменяет значение (записывает результат обратно, даже если он численно идентичен), что может вызвать проблемы с производительностью, поскольку загрязняет строку кэша.
2. @Raymond Спасибо, что добавили это. Каким было бы ваше предпочтительное решение вопроса?
3. Я бы использовал
InterlockedCompareExchange
с маловероятным значением. blogs.msdn.com/10152296.aspx
Ответ №3:
LONGLONG res = InterlockedOr64(amp;m_longlong, 0);
Если ваша программа работает только на 64-разрядной версии, вы можете просто прочитать значение. MSDN утверждает, что
Простые операции чтения и записи в правильно выровненные 64-разрядные переменные являются атомарными в 64-разрядной Windows.
Ответ №4:
С VS 2019 вы должны использовать __iso_volatile_load64
, который является простой загрузкой, поэтому он более эффективен, чем InterlockedCompareExchange64