代码之家  ›  专栏  ›  技术社区  ›  Shcheklein

32位int类型的win-api互锁操作

  •  0
  • Shcheklein  · 技术社区  · 16 年前

    如果我们有:

    __int32 some_var = 0;
    

    打电话最好的方式是什么 InterlockedExchange , InterlockedIncrement 以及其他需要的联锁功能 LONG* 对于 some_var ?

    因为,有保证 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;
    }
    
    6 回复  |  直到 16 年前
        1
  •  0
  •   Mark Ransom    16 年前

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

        2
  •  2
  •   Hans Passant    16 年前

    嗯,这是一块石头和一个坚硬的地方。原子增量是一个繁重的平台实现细节。这就是为什么长typedef首先存在的原因。未来20或50年后的一些操作系统可能会重新定义这种类型。例如,当256位内核很常见并且原子增量的工作方式不同时。谁知道呢。

    如果您想编写真正的可移植代码,那么应该使用真正的可移植类型。喜欢长。让它工作,而不是你的工作,将是微软的负担。

    在很长一段时间内,它将是一个32位整数,我建议您不要担心它。

        3
  •  1
  •   Brent Arias    16 年前

    您也可以将类型更改为long,留下可移植性,因为整个“互锁”原子操作系列也 非便携式 .

    顺便说一句,作为旁注,我认为interlocked支持整数重载。也许这只是在.NET中。

        4
  •  1
  •   caf    16 年前

    好, __int32 不是便携式的吗 任何一个 . 所以我的建议是使用typedef来消除这个问题。在Windows上,您可以执行以下操作:

    typedef LONG my_int32;
    

    …并将指向此类类型的指针安全地传递给 InterlockedExchange() . 在其他系统上,使用32位类型的任何类型-例如,如果它们有 stdint.h 你可以这样做:

    typedef int32_t my_int32;
    
        5
  •  0
  •   Chris Becke    16 年前

    有趣的是, InterlockedExchange -需要很长时间的Windows API*和 _InterlockedExchange 一个MSVC编译器内部函数,需要很长的时间*。

    因为已经调用了可移植性,我还将在 GCC atomic intrinsics .

    然而,这一点是可以理解的:MSVC使用ILP32LLP64 data model 对于32位构建,LLP64对于64位构建。基于gcc的工具链(如mingw)确实存在于Windows中,并且可以很好地实现lp64模型——这会带来有趣的结果!例如“long”是64位,但long是32位。

    如果你坚持使用微软编译器,那就不必担心了。

    因此,综上所述: 1。要传递的值必须用“volatile”限定。 2。因为您(a)使用32位数量(这是您的要求)和(b)使用显式32位形式的interlockedxxx api-它的100%安全,只做血腥的强制转换,并用它来完成:interlockedincrement将在所有位大小的32位值上操作,您的变量将显式32位在所有位大小上-ev使用不同的数据模型。

    演员阵容是安全的,不要无缘无故把事情复杂化。

        6
  •  0
  •   Community Mohan Dere    9 年前

    Hans Passant 表达得很好:

    “原子增量是一个重型平台实现细节。”

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

    atomic_ops 就是这样一个项目。

    理论上,每个互锁功能都可以通过使用完全开放的锁来实现,而完全开放的锁又依赖于平台的具体特性:-),但是对于目标硬件平台上支持的类型和功能来说,这是一个真正的性能过度杀伤力。

    这方面正在进行一些标准化工作,如回答的类似问题。 here 和 here 也。