2

「デッドロック」の他の解釈があるかもしれませんが、AFAIK:

参照

デッドロックは、2 つのスレッドがそれぞれ別のスレッドによって保持されているリソースを待機しているときに発生し、どちらも処理を進めることができません。

しかし、私はSOでここでいくつかの答えを見てきました.

例 #1

namespace ConsoleApplication7
{
    public class Program
    {
        public static void Main(string[] args)
        {
            LockableClass lockable = new LockableClass();
            new Thread(new ParameterizedThreadStart(BackgroundMethod)).Start(lockable);
            Thread.Sleep(500);
            Console.Out.WriteLine("calling Reset");
            lockable.Reset();
        }

        private static void BackgroundMethod(Object lockable)
        {
            lock (lockable)
            {
                Console.Out.WriteLine("background thread got lock now");
                Thread.Sleep(Timeout.Infinite);
            }
        }
    }

    public class LockableClass
    {
        public Int32 Value1 { get; set; }
        public Int32 Value2 { get; set; }

        public void Reset()
        {
            Console.Out.WriteLine("attempting to lock on object");
            lock (this)
            {
                Console.Out.WriteLine("main thread got lock now");
                Value1 = 0;
                Value2 = 0;
            }
        }
    }

}

申し訳ありませんが、ここに表示されるのは、解放されていない純粋なロックだけです。両方のスレッドが別のスレッドを待っている状況ではありません。ここのスレッドは、メイン スレッドが終了するのを待ちません。


別の例 #2

class ILockMySelf
{
    void doThat()
    {
        lock(this){ ... }
    }
}

class WeveGotAProblem
{
    ILockMySelf anObjectIShouldntUseToLock;

    void doThis()
    {
        lock(anObjectIShouldntUseToLock)
        {
            // Following line should run in a separate thread
            // for the deadlock to happen
            anObjectIShouldntUseToLock.doThat();
        }
    }
}

こっちも一緒。実行されるスレッドdoThis は、実行される「別のスレッド」を待っていませんdoThat

質問 :

  • デッドロックはここに関係していますか?
4

3 に答える 3

3

デッドロックの定義が広く、スレッド化以外のシナリオに適用されるという点で、DavidHopeに同意します。ただし、2番目の例は、スレッドを「停止」させる状況がないため、デッドロックではありません。

2番目の例を修正するには、新しいスレッドをスピンアップし、thread1を強制的にthread2で待機させます。次に、デッドロックを作成できます。

//Deadlock
public class Program
{
    public static void Main(string[] args)
    {
        WeveGotAProblem p = new WeveGotAProblem();
        p.doThis();//gain a lock on this thread                        
    }        
}

class ILockMySelf
{
    public void doThat()
    {
        //Thread2 waits on Thread1 to release "this"
        lock (this)
        {
            Console.WriteLine("that");
        }
    }
}

class WeveGotAProblem
{
    ILockMySelf anObjectIShouldntUseToLock = new ILockMySelf();

    public void doThis()
    {
        lock (anObjectIShouldntUseToLock)
        {
            Task task = Task.Factory.StartNew(new Action(() => anObjectIShouldntUseToLock.doThat()));
            Task.WaitAll(task);//Thread1 waits on Thread2 to return.  This is important
        }
    }
}

ここでは、2つ以上の競合するアクションがあり、それぞれが他方の終了を待機しています。

  • スレッド1はthread2が戻るのを待っています。
  • スレッド2は、スレッド1が必要なリソースを解放してから戻るのを待っています。

最初の例(考案されたものの...なぜスレッドを永久にスリープ状態にするのか...?)は、同様の理由でデッドロックを引き起こす可能性があります。

例えば

  • Thread1は、Thread.Sleep()が戻るのを待ちます(決して戻りません)。
  • Thread2は、Thread1がlockableのロックを解放するのを待ちます(決して解放されません)

アクションがスレッドであり、各スレッドが異なる結果を待機しているという事実は、実装の詳細にすぎません。

于 2013-02-22T20:40:31.833 に答える
2

例1について:

私は個人的にこれをデッドロックとは考えていませんが、それは私が「デッドロック」という言葉に付けた意味的な意味のためだけです。確かに、この例ではどちらのスレッドも続行しないため、デッドロックと同じ影響がありますが、各スレッドが他のスレッドによって保持されているリソースを待機しているためではありません。代わりに、実行中のスレッドBackgroundMethod(T1と呼びます)はただ待っています...そして待っています...何も待っていません。T2はT1によって保持されているリソースを待機していないため、実行中のスレッドReset(T2と呼びます)がT11のブロックを解除するために実行できるアクションはありません。私がこれをデッドロックとは見なさないのはこのためです。しかし、他の誰かがそれについて私に同意しない場合、私はあまり不満を抱くつもりはありません。

例2について:

他の人が指摘しているように、これもデッドロックではありません。今回を除いて、どちらのスレッドもブロックしないためです。1つの理由は、alockが再入可能であるためです。ただし、別のスレッドで実行したとしても、すぐにロックが解除されるdoThatため、コードはデッドロックしません。P.Brian.MackeydoThisはすでに彼の答えでこれをかなりうまくカバーしていると思うので、私がこれ以上説明する理由はありません。

今、楽しいもののために

以下は、ロックやブロックの方法が含まれていないため、デッドロックの私のお気に入りの図の1つです。問題の微妙な点は、心の麻痺です。ここでの問題は、メモリバリアがないことに関連しています。スレッドAは、スレッドBが信号フラグを設定するのを待機します。同時に、コンパイラ、JIT、およびハードウェアは自由に最適化できるため、スレッドBはスレッドAが信号フラグをリセットするのを待機します。直感的ではない方法でのフラグの読み取りと書き込み。

この例では、単純な変数boolsignalリソースです。または、より抽象的には、リソースであるのはメモリです。ソフトウェアとハ​​ードウェアの最適化が適用される方法のために、メモリ操作は取得と解放のセマンティクスを持つことができます。これが、メモリバリアの背後にある全体的なポイントです。実際、メモリは他のリソースと同じように操作できるリソースであるため、メモリフェンス(またはバリア)の正式な定義では、取得と解放という用語を使用しています。

免責事項:再現性は、環境とビルド構成によって異なる場合があります。

public class Example
{
  private bool signal = false;

  void ThreadA()
  {
    while (!signal);
    signal = false;
  }

  void ThreadB()
  {
    signal = true;
    while (signal);
  }
}

1完全に衒学的であるために、あなたは電話Thread.Interruptを「突く」ために電話することができThread.Sleepます。

于 2013-02-23T00:42:06.413 に答える
1

本当に、それは の定義に依存するdeadlockため、問題は...

ウィキペディアによると、デッドロックは次のとおりです。

デッドロックとは、2 つ以上の競合するアクションがそれぞれ他のアクションの終了を待っている状態であり、どちらも終了しない状態です。

いずれかの定義から、アクティビティまたはアクションは異なるスレッドにある必要があると推測しますが、これは定義が述べていることではありません。

したがって、技術的には、例 1 はデッドロックではないと結論付けます。これは、バックグラウンド スレッドが (例外の外で) 終了することは決してないためですが、例 2 はデッドロックです。リソース、次に実行フローで問題ありません。

どちらの場合も、プログラミング エラー (#2 はよりエラーであり、#1 は不自然な例のように見えます) があり、コードが先に進まない原因となっています。

したがって、いずれの場合も、単語の特定の意図や用法に関係なく、修正すべき問題があります。deadlock

于 2013-02-22T20:10:31.940 に答える