1

マルチスレッドコードでは、インスタンスが複数のスレッドによって読み取りまたは書き込みされる可能性がある場合、これらの操作を安全に実行するには、インスタンスをロックオンする必要があります。

ロックするオブジェクトの作成とコードによる一連のロックステートメントの記述の繰り返しを避けるために、ロックを処理するジェネリッククラスを作成しました。

概念的に、私は何かが欠けていますか?これはうまくいくはずですよね?

public class Locked<T> where T : new()
{
    private readonly object locker = new object();

    private T value;

    public Locked()
        : this(default(T))
    { }

    public Locked(T value)
    {
        this.value = value;
    }

    public T Get()
    {
        lock (this.locker)
        {
            return this.value;
        }
    }

    public void Set(T value)
    {
        lock (this.locker)
        {
            this.value = value;
        }
    }    
}

そして、クラスで使用されている例:

private Locked<bool> stopWorkerThread = new Locked<bool>();

public void WorkerThreadEntryPoint()
{
    while (true)
    {
        if (this.stopWorkerThread.Get())
        {
            break;

}

また、このようなものを自動化された方法でテストするにはどうすればよいですか(単体テストの作成など)?

最後に、これを回避するために、++および--演算子を実装するために何ができますか?

        this.runningThreads.Set(this.runningThreads.Get() + 1);
4

2 に答える 2

3

これは、get/setの期間中のみロックされます。もちろん、多くの一般的なケースでは、データサイズが原因で、これはとにかくアトミックになります。

ただし、実際には、ほとんどのロックはこれ以上に及ぶ必要があります。これは、コレクションが追加などだけをロックしてもあまり役に立たないのと同じです。呼び出し元は通常、「そこにありますか?更新する場合は、1つのロックが必要です。それ以外の場合は「追加」シーケンス。

ブール値のような単純なものの場合、「揮発性」は問題をはるかに簡単に解決する可能性があります。特に、ループ出口の場合はなおさらです。

[MethodImpl(MethodImplOptions.Synchronized)]も検討することをお勧めします-個人的には、外部の人がオブジェクトをロックする問題を防ぐために、プライベートロックオブジェクト(あなたが使用したような)を好みます(上記では「this」をロックとして使用しています) 。

これを単体テストするには、最初に壊れていることを証明するための何かが必要になります。これは、操作が非常に小さいため(ほとんどのデータ型ではすでにアトミックであるため)難しいでしょう。それが回避する他のことの1つ(volatileも修正する)はレジスターへのキャッシュですが、これも最適化であり、それが壊れていることを証明することを強制するのは困難です。

ロックラッパーに興味がある場合は、このような既存のコードを検討してください。

于 2008-10-05T08:06:29.360 に答える
1

上記のコードには、潜在的で実際のマルチスレッドの問題がかなりあります。実際の状況では、このようなものは使用しません。例えば:

this.runningThreads.Set(this.runningThreads.Get() + 1);

ここにはかなり明白な競合状態があります。呼び出しがGet()戻ると、オブジェクトはロックされなくなります。Get実際のポストまたはプレインクリメントを行うには、カウンタをの前から後までロックする必要がありますSet

また、同期読み取りだけを実行している場合は、必ずしも完全ロックを実行する必要はありません。

より良いロックインターフェースでは、(私が思うに)それを行う必要がある場所でインスタンスを明示的にロックする必要があります。私の経験は主にC++であるため、完全な実装をお勧めすることはできませんが、私の好みの構文は次のようになります。

using (Locked<T> lock = Locked<T>(instance))
{
  // write value
  instance++;
}

// read value
print instance;
于 2008-10-05T08:11:05.853 に答える