4

マルチスレッドを多用するアプリケーションを書いています。一部のスレッドは、ReaderWriterLockSlim を使用して observablecollection を共有します。

私は時々デッドロックを抱えており、デッドロックの瞬間にロックを保持しているスレッドを知る必要があります。どうすればこれを知ることができますか? オブジェクトのプロパティを調べましたが、明らかなものは何もありませんでした。現在、私が知っているのは、どのスレッドがロックを待っているかだけです。

ご協力いただきありがとうございます!

編集:もちろん、デバッグ時にすべてのデバッグ情報を利用できるようにすることについて話している。

4

5 に答える 5

3

デッドロック中に、スレッドデバッグパネルで現在のスレッドを確認し、呼び出しスタックを調べると、どのスレッドがロックを取得したかがわかります。

コード内のスレッドIDを知る必要がある場合は、いつでも静的に保存するか、readerwriterlockslimから継承してスレッドプロパティを追加できます。

于 2012-05-23T20:30:00.317 に答える
3

これが私が意味したことです。
ロックとロック解除をトレースするだけで、デッドロックに到達するとシステムが停止し、最後の「Enter」キーでロック スレッドの方向が示されます。

public class ReaderWriterLockSlimExtended : ReaderWriterLockSlim
{
    private Thread m_currentOwnerThread = null;
    private object m_syncRoot = new object();

    public Thread CurrentOwnerThread
    {
        get
        {
            lock (m_syncRoot)
            {
                return m_currentOwnerThread;
            }
        }
    }

    public Thread CurrentOwnerThreadUnsafe
    {
        get
        {
            return m_currentOwnerThread;
        }
    }

    public new void EnterWriteLock()
    {
        lock (m_syncRoot)
        {
            base.EnterWriteLock();
            m_currentOwnerThread = Thread.CurrentThread;
        }
        Debug.WriteLine("Enter Write Lock - Current Thread : {0} ({1})", CurrentOwnerThread.Name, CurrentOwnerThread.ManagedThreadId);
    }

    public new void ExitWriteLock()
    {
        Debug.WriteLine("Exit Write Lock - Current Thread : {0} ({1})", CurrentOwnerThread.Name, CurrentOwnerThread.ManagedThreadId);
        lock (m_syncRoot)
        {
            m_currentOwnerThread = null; //Must be null before exit!
            base.ExitWriteLock();
        }
    }  
}
于 2012-05-24T19:50:42.040 に答える
2

ロックの直前と直後にいつでもスレッド ID をトレースしてみることができるので、何が起こったのか、誰がいつロックしたのかを記録できます。ファイルに書き込むか、デバッガーの出力ウィンドウでチェックインして、すべてのトレースを確認できます。実際のトレース コードの代わりにトレース ブレークポイント (Breakpoint -> When Hit...) を使用して、出力ウィンドウにすばやく何かを表示できると思います。

于 2012-05-23T20:43:29.477 に答える
2

ReaderWriterLockSlimは封印されていないため、サブクラス化して、必要な情報をそのように添付できます。問題は、便利なメソッドが仮想ではないため、オーバーライドできないことです。ただし、メソッドが呼び出されたスレッドをキャプチャするだけでなく、バ​​ックグラウンドで呼び出すなどのEnterReadLockDebug独自のメソッドを追加することもできます。すべての呼び出しサイトを変更する必要があるため、これは優れたソリューションではありません。ただし、デバッガーの使用が面倒な場合は、これが合理的な代替手段になるかもしれません。ExitReadLockDebugEnterReadLockExitReadLock

条件付きコンパイルを使用したテーマには、さまざまなバリエーションがあります。デバッグ ビルドとリリース ビルドを検出し、アクティブなビルド構成に応じて必要なデバッグ ロジックを挿入できます。Debug がアクティブなときにデバッグ情報を挿入し、Release がアクティブなときにそれを省略します。

于 2012-05-23T21:12:58.447 に答える
0

これは、将来の参考のために、私が終了したコードです。

using System;
using System.Threading;

namespace Utils
{
public class ReaderWriterLockSlim2
{
    #region Attributes

    private readonly TimeSpan _maxWait;
    private readonly ReaderWriterLockSlim _lock;

    #endregion

    #region Properties

    public int CurrentWriteOwnerId { get; private set; }
    public string CurrentWriteOwnerName { get; private set; }

    #endregion

    #region Public Methods

    public ReaderWriterLockSlim2(LockRecursionPolicy policy, TimeSpan maxWait)
    {
        _maxWait = maxWait;
        _lock = new ReaderWriterLockSlim(policy);
    }

    public void EnterWriteLock()
    {
        if (!_lock.TryEnterWriteLock(_maxWait))
        {
            throw new TimeoutException(string.Format("Timeout while waiting to enter a WriteLock. Lock adquired by Id {0} - Name {1}", this.CurrentWriteOwnerId, this.CurrentWriteOwnerName));
        }
        else
        {
            this.CurrentWriteOwnerId = Thread.CurrentThread.ManagedThreadId;
            this.CurrentWriteOwnerName = Thread.CurrentThread.Name; 
        }
    }

    public void ExitWriteLock()
    {
        _lock.ExitWriteLock();
        this.CurrentWriteOwnerId = 0;
        this.CurrentWriteOwnerName = null;  
    }

    public void EnterReadLock()
    {
        _lock.EnterReadLock();
    }

    public void ExitReadLock()
    {
        _lock.ExitReadLock();
    }

    #endregion
}
}
于 2012-05-24T12:54:23.370 に答える