2012-06-06 3 views
0

Во-первых, у нас есть InterlockedExchange64();Непоследовательная документация MSDN для функций/встроенных функций InterlockedExchange()?

http://msdn.microsoft.com/en-us/library/windows/desktop/ms683593%28v=vs.85%29.aspx

LONGLONG __cdecl InterlockedExchange64(__inout LONGLONG volatile *Target, __in LONGLONG Value); 

Во-вторых, у нас есть компилятор характеристическая, _InterlockedExchange64(), обратите внимание на отсутствие летучих;

http://msdn.microsoft.com/en-us/library/1s26w950%28v=vs.80%29.aspx

__int64 _InterlockedExchange64(__int64 * Target, __int64 Value); 

Далее, мы имеем InterlockedExchangePointer(), который, как InterlockedExchange64(), использует летучий.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms683609%28v=vs.85%29.aspx

PVOID __cdecl InterlockedExchangePointer(__inout PVOID volatile *Target, __in PVOID Value); 

Но теперь мы приходим к внутреннему для обмена указателей, _InterlockedExchangePointer() и здесь мы видим, летучими используются!

http://msdn.microsoft.com/en-us/library/853x471w.aspx

void * _InterlockedExchangePointer(void * volatile * Target, void * Value); 

Основная инструкция одинакова во всех случаях, так что это дает? ошибка документации?

GCC instrincs не упоминает volatile для обмена, но тогда они не упоминают его для CAS! так что это не помогает.

Мое мнение, что цель CAS нестабильна, потому что вы можете знать только во время выполнения, если произойдет обмен; но атомный обмен не должен быть изменчивым, потому что цель всегда обновляется (даже если это значение не изменяется), поэтому у компилятора нет неопределенности.

Я также вижу, что функция InterlockedIncrement() нестабильна, но instrincs нет. Внутренние возможности для CAS нестабильны для их назначения.

ответ

3

MSDN пронизана в основном незначительными ошибками документации (например, __readfsdword был помечен как ядро ​​только в документах VS 2005), на что вы должны обратить внимание, это определение, которое использует компилятор, в данном случае, определения в intrin.h (из VS2010 Окончательной SP1):

__MACHINEI(long _InterlockedExchange(long volatile *, long)) 
__MACHINEIA64(__int64 _InterlockedExchange64(__int64 volatile *, __int64)) 

, как мы можем видеть, что они действительно volatile указатели, которые необходимы.

В заключение отметим, что все ваши ссылки - документы VS 2005 (по умолчанию связанные с google для более старых встроенных функций), поэтому убедитесь, что вы используете раскрывающийся список в верхней части страницы, чтобы перейти к последним версиям.

+0

Thankyou очень много! теперь нужно исправить некоторый код ... :-) –

+0

Должен сказать, что я озадачен. Почему для обмена требуется летучая цель? результат операции всегда предсказуем. –

+0

@BlankXavier: IIRC ему требуется летучая мишень, чтобы он мог обеспечить барьер уровня уровня компилятора, в то время как фактическая команда prefixed 'LOCK' обеспечивает уровень защиты памяти уровня процессора. – Necrolis

1

Это не то, что указатель на летучее это требуется от этих функций является, что разрешено.То есть, если параметры были объявлены до тех пор, * вместо длинных летучий * затем передавая адрес изменчивой переменной даст эту ошибку:

cannot convert argument 1 from 'volatile LONGLONG *' to 'LONGLONG *' 

Это можно увидеть с помощью этого простого кода:

LONGLONG a; 
volatile LONGLONG b; 

void DoSomething(LONGLONG* p) {} 

int main() { 
    DoSomething(&a); 
    DoSomething(&c); // Error! 
    return 0; 
} 

В C/C++ существует давняя традиция злоупотребления волатильностью, чтобы указать, что переменная может быть изменена другими потоками. Это ошибочно, потому что волатильность на самом деле не дает значимой полезной семантики для многопоточности, но когда C++ не признает, что многопоточные разработчики отчаялись. Проблема с использованием volatile заключается в том, что он не мешает переупорядочению компилятора или процессора, поэтому он ошибочен, скажем, 99% времени в многопоточном коде.

Отсутствие C++ 11 безопасная вещь - это всегда ссылаться на эти переменные, совместно используемые с использованием функций Interlocked *. Если вы это сделаете, то волатильность не нужна. Или используйте замки, как здравомыслящий человек.

Но, поскольку многие разработчики отмечают свои потоковые общие переменные атомарными, необходимо, чтобы функции Interlocked * принимали эти переменные. И именно поэтому все они берут тип указателя на летучесть.

+1

Видя как вопрос помечен специальными материалами MS, вам нужно будет принять во внимание, что VS позволяет 'volatile' давать переменную для получения и выпуска семантики (посредством возможного испускания дополнительного кода, кроме ARM); см. конкретную часть MS в конце страницы на странице «volatile»: https://msdn.microsoft.com/en-us/library/12a04hfd(v=vs.140).aspx – Necrolis

+1

True - начиная с VS 2005 volatile была задана специальная семантика MS. Однако VS теперь пытается их отбросить - ключевое слово/volatile поддерживает это, и в его документации говорится: «Мы настоятельно рекомендуем использовать/volatile: iso» Так что да, имея в виду, что VC++ специфическое значение volatile является разумным для этого вопрос. Но если вы используете volatile для многопоточности, вы должны остановиться. Это нестандартное использование для него, и для этого требуется полный абзац, объясняющий, при каких условиях он действителен (VC++ 2005+, если VC++ 2012 или выше должен использовать/volatile: ms if on ARM). –