2

char または short で _Interlocked*** 関数を使用する必要がありますが、入力として long ポインターが必要です。関数 _InterlockedExchange8 があるようですが、それに関するドキュメントはありません。これは文書化されていない機能のようです。また、コンパイラは _InterlockedAdd8 関数を見つけることができませんでした。その機能、使用する/使用しないことの推奨事項、およびその他の解決策に関する情報をいただければ幸いです。

更新 1

質問を単純化してみます。どうすればこれを機能させることができますか?

struct X
{
    char data;
};

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

考えられる解決策が 2 つあります

  1. 使用する_InterlockedExchange8
  2. long にキャストanotherし、交換を行い、結果を X にキャストします

最初のものは明らかに悪い解決策です。2 番目の方が見栄えが良いですが、どのように実装しますか?

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

より小さなデータ型を使用したいのはなぜですか? では、小さなメモリ空間にそれらの束を収めることができますか? これは、誤った共有とキャッシュ ラインの競合につながるだけです。

ロック アルゴリズムを使用するかロックレス アルゴリズムを使用するかに関係なく、一度に 1 つのスレッドだけが使用する、少なくとも 128 バイト (または CPU のキャッシュ ラインのサイズに関係なく) のブロックにデータを配置するのが理想的です。

于 2011-02-22T05:33:52.070 に答える
1

まあ、利用可能な機能で間に合わせる必要があります。_InterlockedIncrementおよび `_InterlockedCompareExchange は 16 ビットおよび 32 ビットのバリアント (後者は 64 ビットのバリアントでも) で利用可能であり、おそらく他のいくつかのインターロックされた組み込み関数は 16 ビット バージョンでも利用可能ですが、InterlockedAdd はそうではないようです。 、バイトサイズのインターロック組み込み関数/関数はまったくないようです。

だから... 一歩下がって、. なしで問題を解決する方法を見つける必要がありますIntrinsicAdd8

いずれにせよ、なぜ個々のバイトで作業しているのですか? intより小さなものを使用する本当に正当な理由がない限り、 のサイズのオブジェクトに固執してください。

于 2011-02-22T07:54:55.183 に答える
1

あなたの編集が少し変わったので、新しい答えを作成します:

  • _InterlockedExchange8 を使用
  • 別のものをロングにキャストし、交換を行い、結果をXにキャストします

最初のものは単に機能しません。関数が存在したとしても、一度に 1 バイトずつアトミックに更新できます。これは、オブジェクト全体がアトミックではない一連のステップで更新されることを意味します。

XサイズのlongPODタイプでない限り、2番目も機能しません。(および、sizeof(long)境界上に配置されていない限り、および a と同じサイズでない限りlong)

この問題を解決するには、どのタイプが考えられるかを絞り込む必要がXあります。まず、もちろんPOD型であることが保証されているのですか?そうでない場合は、POD 以外の型を生のメモリ バイトとして安全に扱うことができないため、まったく別の問題が発生します。

第二に、どのようなサイズがXありますか? インターロック機能は、16、32、状況によっては 64 または 128 ビット幅を処理できます。

それはあなたが遭遇する可能性のあるすべてのケースをカバーしていますか?

そうでない場合は、これらのアトミック操作を放棄し、単純な古いロックに落ち着かなければならない場合があります。Mutex をロックして、一度に 1 つのスレッドのみがこれらのオブジェクトにアクセスするようにします。

于 2011-02-22T09:48:09.643 に答える