2

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

更新 1

我会尽量简化这个问题。我怎样才能使这项工作?

struct X
{
    char data;
};

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

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

  1. 利用_InterlockedExchange8
  2. 转换another为 long,进行交换并将结果转换回 X

第一个显然是不好的解决方案。第二个看起来更好,但是如何实现呢?

更新 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

4 回答 4

2

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

互锁 API 实现示例:intrin.asm

于 2011-04-04T06:19:48.320 回答
1

创建一个新答案,因为您的编辑改变了一些事情:

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

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

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

为了解决这个问题,您需要缩小X可能的类型。首先,当然,保证是POD类型吗?如果不是,您将遇到一个完全不同的问题,因为您不能安全地将非 POD 类型视为原始内存字节。

其次,可能有哪些尺寸X?Interlocked 函数可以处理 16、32 位宽度,根据具体情况,可能是 64 位甚至 128 位宽度。

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

如果没有,您可能不得不放弃这些原子操作,而接受普通的旧锁。锁定一个 Mutex 以确保一次只有一个线程接触这些对象。

于 2011-02-22T09:48:09.643 回答
1

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

所以...您需要退后一步,弄清楚如何在没有IntrinsicAdd8.

无论如何,您为什么要使用单个字节?int除非您有充分的理由使用较小的对象,否则请坚持使用尺寸较小的对象。

于 2011-02-22T07:54:55.183 回答
1

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

无论您使用锁定算法还是无锁算法,理想的做法是让您的数据以至少 128 字节的块(或 CPU 上的任何高速缓存行大小)一次仅由单个线程使用。

于 2011-02-22T05:33:52.070 回答