2010-09-03 2 views
0

Если мы имеем:операции Win API ВЗАИМОСВЯЗАННОГО для 32-битного целого типа

__int32 some_var = 0; 

Что является лучшим (если таковые имеются) способ вызова InterlockedExchange, InterlockedIncrement и другие сблокированные функции, которые требуют LONG* для some_var?

Поскольку есть гарантия, что LONG - 32 бит на любой Windows, возможно, безопасно просто пройти (long*) some_var. Тем не менее, мне кажется довольно уродливым, и я не могу найти подтверждения, что это безопасно.

Примечание. Я не могу изменить тип на long, потому что он не переносится. Мне нужен ровно 32-битный тип.

Обновление: Некоторые исследования библиотек, которые обеспечивают переносные атомные операции, показали, что никто не беспокоится о литье. Некоторые примеры:

Apache Portable Runtime (APR):

typedef WINBASEAPI apr_uint32_t (WINAPI * apr_atomic_win32_ptr_val_fn) 
    (apr_uint32_t volatile *, 
    apr_uint32_t); 

APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val) 
{ 
#if (defined(_M_IA64) || defined(_M_AMD64)) 
    return InterlockedExchangeAdd(mem, val); 
#elif defined(__MINGW32__) 
    return InterlockedExchangeAdd((long *)mem, val); 
#else 
    return ((apr_atomic_win32_ptr_val_fn)InterlockedExchangeAdd)(mem, val); 
#endif 
} 

atomic_ops:

AO_INLINE AO_t 
AO_fetch_and_sub1_full (volatile AO_t *p) 
{ 
    return _InterlockedDecrement64((LONGLONG volatile *)p) + 1; 
} 
+0

http://stackoverflow.com/questions/930897/c-atomic-operations-for-lock-free-structures http://stackoverflow.com/questions/523827/c0x-atomic-template-implementation –

ответ

0

Просто сделайте assert(sizeof(LONG) == sizeof(some_var)) и беспокоитесь только о проблеме, когда утверждение не выполнено. YAGNI. Пока это утверждение выполняется, вы можете использовать reinterpret_cast<LONG*>(&some_var).

+0

Размеры теперь равны в Windows (и я всегда верю). Предполагая, что это безопасное литье и почему? – Shcheklein

+0

@Schcheklein, я предполагаю, что указатели на целые типы одного размера могут быть смещены друг к другу, потому что представление машины одинаково; даже если они не совпадают, например, несоответствие подписанного/неподписанного, разница должна быть безвредной.Я полагаю, что LONG может включать какое-то ключевое слово выравнивания для Microsoft, поэтому я не могу делать никаких абсолютных гарантий. Это все вуду, специфичное для реализации, поэтому вам придется полагаться на некоторые предположения и принимать некоторые компромиссы. –

+0

Я верю, что вы правы. По крайней мере, кажется, никто не беспокоится о кастинге. См. Также вопросы об обновлениях. – Shcheklein

1

Вы могли бы также изменить тип на долго, оставляя за портативности, так как весь "блокированы" семейство атомарных операций также не переносится.

Кстати, в качестве побочного примечания я думал, что блокировка поддерживает целую перегрузку. Возможно, это только в .net.

+0

Просто Я сказал, что * * не могу изменить тип. Но я могу (и это обычный способ) написать переносимый «MyPortableInterlockedExchangeWrapper» (конечно, есть безопасный способ передать int в InterlockedExchange в Windows). – Shcheklein

2

Ну, это камень и трудное место. Атомное приращение представляет собой детальную реализацию платформы с большой нагрузкой. Вот почему LONG typedef существует в первую очередь. Некоторая будущая операционная система через 20 или 50 лет может переопределить этот тип. Когда, скажем, 256-битные ядра являются общими, а атомные приращения работают по-разному. Кто знает.

Если вы хотите написать действительно портативный код, тогда вы должны использовать действительно переносные типы. Как ДОЛГО. И это будет бременем Microsoft, чтобы заставить его работать вместо ваших.

Это будет 32-битное целое число в течение довольно долгого времени, я бы рекомендовал вам не беспокоиться об этом.

+0

@ Ханс: Почему возникла проблема с предоставлением 'InterlockedExchange32'? Существуют функции для 64-битных целых чисел, и они работают с типом __int64. – Shcheklein

+0

@ Hans: LONG совсем не переносится. Он работает только на MS, но мне нужен 32-разрядный переносной тип. – Shcheklein

+0

@Hans: Является ли '(LONG *) & some_var' действительным и безопасным? Почему компилятор не делает это автоматически, если это безопасно? – Shcheklein

1

Ну, не является переносным типом . Поэтому мое предложение по устранению проблемы - использовать typedef. В Windows, вы можете сделать:

typedef LONG my_int32; 

... и безопасно передать указатель на такой тип для InterlockedExchange(). В других системах, использовать все это 32 бит типа там - например, если у них есть stdint.h, вы можете сделать:

typedef int32_t my_int32; 
+0

Мы уже используем 'stdint.h' (есть также реализация для Windows). Я использовал '__int32' просто для простоты в моем вопросе. – Shcheklein

+0

Я не люблю вводить новые типы только из-за одной функции, но, вероятно, это единственный способ. – Shcheklein

0

достаточно Занятно, есть InterlockedExchange - это окна API, который принимает LONG * и _InterlockedExchange msvc встроенный, который занимает длинный *.

Поскольку мобильность была вызвана, Ill также ссылается на страницу на GCC atomic intrinsics.

Точка хорошо взята: MSVC использует ILP32LLP64 data model для 32-битных сборок и LLP64 для 64-битных сборок. Комбинированные на основе GCC (например, MinGW) существуют для окон и могут очень хорошо реализовать модель LP64, что приводит к забавному! таких как «длинный», 64 бит, но LONG равен 32.

Если вы придерживаетесь компиляторов Microsoft, вам не о чем беспокоиться.

Итак, в заключение: 1. Передаваемая стоимость ДОЛЖНА быть квалифицирована как «изменчивый». 2. Потому что вы (a) используете 32-битное количество (и это требование youre) и (b), используя явно 32-битную форму InterlockedXXX API - ее 100% -ный сейф, чтобы просто сделать чертову бросок и сделать с ней: InterlockedIncrement будет работать с 32-битным значением для всех размеров бит, ваша переменная будет явно 32 бит на всех размерах бит - даже при использовании разных моделей данных.

литье безопасно, не перегружайте вещи без причины.

0

Hans Passant выразил это очень хорошо:

«Атомное приращение представляет собой сверхмощная деталь реализации платформы.»

Именно поэтому реализации обеспечивают специфические перегрузки типа.

atomic_ops является одним из таких проектов.

Теоретически, каждая функция блокировки может быть реализована с использованием полномасштабных замков, которые в свою очередь полагаются на специфику платформы :-) - но это реальная перегрузка производительности для типов и функций, которые поддерживаются на целевом оборудовании Платформа.

В этом отношении происходит стандартизация, см., Например, аналогичные вопросы ответили here и here.

Смежные вопросы