32位整型

问题描述:

赢API互锁操作如果我们有:32位整型

__int32 some_var = 0; 

什么是最好的(如果有的话)的方式来调用InterlockedExchangeInterlockedIncrement等互锁功能,这需要LONG*some_var

因为,在任何Windows上都有保证LONG是32位的,所以通过(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 – 2010-09-05 01:02:10

只要做assert(sizeof(LONG) == sizeof(some_var)),只有当断言失败时才担心这个问题。 YAGNI。只要断言成立,你可以使用reinterpret_cast<LONG*>(&some_var)

+0

现在Windows上的大小是相等的(我相信总是会的)。假设这是安全的,为什么? – Shcheklein 2010-09-03 17:22:26

+0

@Shcheklein,我假设指向相同大小的整数类型的指针可以安全地相互转换,因为机器表示是相同的;即使它们不是相同的,例如有符号/无符号不匹配,差异也应该是无害的。我猜想'LONG'可以包含一些微软特定的对齐关键字,所以我不能做出任何绝对的保证。这是所有特定于实现的巫术,所以你将不得不依靠一些假设并接受一些折衷。 – 2010-09-03 17:40:23

+0

我相信你是对的。至少似乎没有人会关注铸造。另请参阅问题更新。 – Shcheklein 2010-09-08 10:00:50

你不妨类型更改为长,留下的便携性,因为整个 “联锁” 家庭原子操作的也不可移植

顺便提及,作为边注,还以为互锁支撑的整数过载。也许这只是在.NET中。

+0

Just我说我*不能*改变类型。但我可以(也是常用的方法)编写可移植的'MyPortableInterlockedExchangeWrapper'(当然,有一种安全的方法可以将int传递给Windows上的'InterlockedExchange')。 – Shcheklein 2010-09-03 15:22:44

嗯,这是一个进退两难的地方。原子增量是一个沉重的平台实现细节。这就是为什么LONG typedef首先存在的原因。 20或50年后的一些未来操作系统可能会重新定义这种类型。例如,当256位内核是常见的,原子增量的工作方式不同。谁知道。

如果你想写真正的便携式代码,那么你应该使用真正的便携式类型。像LONG一样。这将是微软的工作负担,而不是你的。

这将是一个32位整数相当长的一段时间,我建议你不要担心它。

+0

@Hans:为什么提供'InterlockedExchange32'是个问题?有64位整数函数,它们使用__int64类型。 – Shcheklein 2010-09-03 16:31:28

+0

@Hans:LONG根本不是便携式的。它只适用于MS,但我需要32位便携式。 – Shcheklein 2010-09-03 16:32:30

+0

@Hans:'(LONG *)&some_var'是否有效且安全?为什么编译器在安全的情况下自动编译它? – Shcheklein 2010-09-03 16:35:32

那么,不是便携式要么。所以我的建议是让问题消失,就是使用typedef。在Windows中,你可以这样做:

typedef LONG my_int32; 

...和一个指向安全通过这种类型InterlockedExchange()。在其他系统上,使用什么是一个32位的类型有 - 例如,如果他们有stdint.h,你可以这样做:

typedef int32_t my_int32; 
+0

我们已经使用'stdint.h'(Windows也有实现)。在我的问题中,为了简单起见,我使用了__int32。 – Shcheklein 2010-09-04 11:54:39

+0

我不喜欢仅仅因为一种功能而引入新的类型,但可能它是唯一的方法。 – Shcheklein 2010-09-04 11:56:16

有趣的是足够的,有InterlockedExchange - 一个Windows API,它需要很长的*和_InterlockedExchange一msvc编译器内在,需要很长的*。

由于可移植性已被调用,所以我也链接了一个页面GCC atomic intrinsics

不过这一点很明显:MSVC使用32位版本的ILP32LLP64 data model和64位版本的LLP64。基于GCC的工具链(例如MinGW)确实存在于Windows中,并且可能很好地实现了LP64模型 - 导致有趣!例如'long'是64位,但LONG是32.

如果您坚持使用Microsoft编译器,那么您不需要担心。

因此,总结: 1.传递的值必须用'volatile'限定。 2.因为你是(a)使用32位数量(这是你的要求)和(b)使用InterlockedXXX API的明确的32位形式 - 它的100%安全只是做血腥的演员,并用它来完成: InterlockedIncrement将对所有位大小的32位值进行操作,即使使用不同的数据模型,您的变量也将在所有位大小上明确显示为32位。

演员是安全的,不要过于复杂的事情无缘无故。

Hans Passant已经表达得很好:

“一个单位递增是重型平台实现的细节。”

这就是实现提供类型特定重载的原因。

atomic_ops就是这样一个项目。

从理论上讲,每个互锁函数都可以通过使用全发锁来实现 - 它依次依赖平台细节:-) - 但是这对于目标硬件所支持的类型和函数是一种真正的性能过度消耗平台。

在这方面正在进行一些标准化,类似的问题也回答了herehere