WinAPI _Interlocked * char的内部函数,简称

时间:2011-02-22 05:29:40

标签: c++ winapi intrinsics interlocked

我需要在char或short上使用_Interlocked ***函数,但它需要长指针作为输入。似乎有函数_InterlockedExchange8,我没有看到任何文档。看起来这是无证件的功能。编译器也无法找到_InterlockedAdd8函数。 我将非常感谢有关该功能的任何信息,使用/不使用的建议以及其他解决方案。

更新1

我会尝试简化问题。 我怎样才能做到这一点?

struct X
{
    char data;
};

X atomic_exchange(X another)
{
    return _InterlockedExchange( ??? );
}

我看到两种可能的解决方案

  1. 使用_InterlockedExchange8
  2. another转换为long,进行交换并将结果转换回X
  3. 第一个显然是糟糕的解决方案。 第二个看起来更好,但如何实现呢?

    更新2

    你怎么看待这样的事情?

    template <typename T, typename U>
    class padded_variable
    {
    public:
        padded_variable(T v): var(v) {}
        padded_variable(U v): var(*static_cast<T*>(static_cast<void*>(&v))) {}
        U& cast()
        {
            return *static_cast<U*>(static_cast<void*>(&var));
        }
        T& get()
        {
            return var;
        }
    private:
        T var;
        char padding[sizeof(U) - sizeof(T)];
    };
    
    struct X
    {
        char data;
    };
    
    template <typename T, int S = sizeof(T)> class var;
    template <typename T> class var<T, 1>
    {
    public:
        var(): data(T()) {}
        T atomic_exchange(T another)
        {
            padded_variable<T, long> xch(another);
            padded_variable<T, long> res(_InterlockedExchange(&data.cast(), xch.cast()));
            return res.get();
        }
    private:
        padded_variable<T, long> data;
    };
    

    感谢。

4 个答案:

答案 0 :(得分:2)

制作8位和16位互锁功能非常容易,但它们未包含在WinAPI中的原因是由于IA64的可移植性。如果你想支持Win64,汇编程序不能内联,因为MSVC不再支持它。作为外部功能单元,使用MASM64,它们不会像内联代码或内在函数那样快,因此您更明智地研究促进算法使用32位和64位原子操作。

示例互锁API实施:intrin.asm

答案 1 :(得分:1)

为什么要使用较小的数据类型?那么你可以将它们放在一个小的内存空间中吗?这只会导致错误的共享和缓存行争用。

无论您使用锁定算法还是无锁算法,最好将数据保存在至少128字节(或CPU上的任何高速缓存行大小)的块中,这些块一次只能由一个线程使用。

答案 2 :(得分:1)

嗯,你必须使用可用的功能。 _InterlockedIncrement和`_InterlockedCompareExchange提供16位和32位变体(后者也是64位变体),也许其他一些互锁内在函数也可用于16位版本,但InterlockedAdd不具备此功能。似乎是,似乎根本没有字节大小的互锁内在函数/函数。

所以......你需要退后一步,找出如何在没有IntrinsicAdd8的情况下解决问题。

在任何情况下,为什么要使用单个字节?坚持int大小的对象,除非你有充分的理由使用更小的东西。

答案 3 :(得分:1)

创建新答案,因为您的编辑稍微改变了一点:

  
      
  • 使用_InterlockedExchange8
  •   
  • 将另一个转换为long,进行交换并将结果转换回X
  •   

第一个根本行不通。即使函数存在,它也允许您一次原子地更新一个字节。这意味着对象作为一个整体将在一系列步骤中更新,不会是原子的。

除非Xlong大小的POD类型,否则第二个也不起作用。 (除非它在sizeof(long)边界上对齐,除非它与long的大小相同)

为了解决这个问题,您需要缩小X类型的范围。首先,当然,它是否保证是POD类型?如果没有,你有一个完全不同的问题,因为你无法安全地将非POD类型视为原始内存字节。

其次,X可能具有哪些尺寸?互锁功能可以处理16,32,并根据情况,可能是64位甚至128位宽。

这是否涵盖了您可能遇到的所有情况?

如果没有,你可能不得不放弃这些原子操作,并解决普通的旧锁。锁定互斥锁以确保一次只有一个线程接触这些对象。