7

免責事項: 私の投稿は明らかに常に冗長です。タイトルの質問に対する答えをたまたま知っている場合は、以下の詳細な説明を読まずに、自由に答えてください。


このSystem.Threading.Interlockedクラスは、スレッドセーフなコードの記述を支援する非常に便利なメソッドをいくつか提供します。より複雑なメソッドの 1 つに がありますCompareExchange。これは、複数のスレッドから更新される可能性のある実行中の合計を計算するために使用できます。

の使用はCompareExchange少しトリッキーなので、いくつかのヘルパー メソッドを提供するのはかなり常識的な考えだと思いました。

// code mangled so as not to require horizontal scrolling
// (on my monitor, anyway)
public static double Aggregate
(ref double value, Func<double, double> aggregator) {
    double initial, aggregated;

    do {
        initial = value;
        aggregated = aggregator(initial);
    } while (
        initial != Interlocked.CompareExchange(ref value, aggregated, initial)
    );

    return aggregated;
}

public static double Increase(ref double value, double amount) {
    return Aggregate(ref value, delegate(double d) { return d + amount; });
}

public static double Decrease(ref double value, double amount) {
    return Aggregate(ref value, delegate(double d) { return d - amount; });
}

さて、おそらく私はジェネリックに満足しているという罪を犯しているだけです(認めますが、これは多くの場合真実です)。しかし、上記のメソッドによって提供される機能を値のみに制限するのはばかげているように感じdoubleます (または、より正確には、サポートしたいすべての型に対して上記のメソッドのオーバーロードされたバージョンを作成する必要があります)。なぜ私はこれを行うことができないのですか?

// the code mangling continues...
public static T Aggregate<T>
(ref T value, Func<T, T> aggregator) where T : IEquatable<T> {
    T initial, aggregated;

    do {
        initial = value;
        aggregated = aggregator(initial);
    } while (
        !initial.Equals(
            Interlocked.CompareExchange<T>(ref value, aggregated, initial)
        )
    );
}

Interlocked.CompareExchange<T>どうやらwhere T : class制約があるため、これを行うことはできません。理由がわかりません。つまり、accept 、、などのオーバーロードが既に存在するためかもしれません。しかし、それは正当な理由とは思えません。たとえば、私の場合、このメソッドを使用してさまざまな原子計算を実行できると非常に便利です。CompareExchangeInt32Int64DoubleAggregate<T>

4

3 に答える 3

12

Interlocked.CompareExchangeプロセッサによって直接提供されるネイティブのアトミック命令で実装されることを意図しています。そのようなものをlock内部で使用するのは無意味です (ロックフリーのシナリオ用に設計されています)。

アトミック比較交換命令を提供するプロセッサは、小さな「レジスタサイズ」の操作としてそれを自然にサポートします (たとえば、Intel x64 プロセッサで最大の比較交換命令はcmpxchg16b128 ビット値で動作します)。

任意の値型はそれよりも大きくなる可能性があり、単一の命令では比較交換できない場合があります。参照型の比較交換は簡単です。メモリ内の合計サイズに関係なく、既知のサイズの小さなポインターを比較してコピーします。Int32これは、 やなどのプリミティブ型にも当てはまりますDouble。それらはすべて小さいです。

于 2010-02-11T01:11:46.140 に答える
1

そのオーバーロードは、参照を比較および交換することを特に意図しているためです。Equals() メソッドを使用した等価チェックは実行しません。値型は、比較対象の値と参照が等しいことは決してないため、誤用を防ぐために T をクラスに制約したと思います。

于 2010-02-11T01:13:20.387 に答える
-1

Interlocked.CompareExchange<T>ボンネットの下でアトミックポインタースワップを実行するだけだと思います。

値型でこれを行おうとすると、期待した結果が得られない可能性があります。

objectもちろん、値の型を使用する前にボックス化することもできます。

于 2010-02-11T01:09:47.340 に答える