1

私はそれを説明する方法がわかりませんが、コードが適切に記述されている場合に場所を持ってはならないという例外が発生しています。この例外は ReaderWriterLockSlim の問題に関するものであり、LockRecursionException です。「ScreenLocker.EnterReadLock();」に表示されています ライン。私のコードとインターネットで何をすべきか、または何が問題なのかについての説明の問題が見つかりません。そのため、ここにこの質問を書き、皆さんに助けを求めます。これは私が問題を抱えているコードです:

public static List<Dictionary<int, int>> RunTasks(ScreenScanning ss)
    {
        var listOfTasks = new List<Task>();
        List<Dictionary<int, int>> PosXOfBlocksAndMeaningOfIt = new List<Dictionary<int, int>>();
        for (var i = 0; i <= BlocksOnYAxisOnScreen; i++)
        {
            ScreenLocker.EnterReadLock();
            var t = new Task(() =>
            {
                PosXOfBlocksAndMeaningOfIt.Add(ss.XAxysScan(PosYOfRowsToScan[i], Screen, ref ScreenLocker));
            });
            listOfTasks.Add(t);
        }
        Task.WaitAll(listOfTasks.ToArray());
        return PosXOfBlocksAndMeaningOfIt;
    }

そして、それはこのメソッドによって呼び出される関数です:

public Dictionary<int, int> XAxysScan(int posY, Bitmap screen, ref ReaderWriterLockSlim screenLocker)
    {
        screenLocker.ExitReadLock();
        Dictionary<int, int> partOfMainTable = new Dictionary<int, int>();
        partOfMainTable.Add(666, posY); //used in BotViewUpdate in DataToTableInterpreter
        for (int i = 0; i <= 1920; i++)
        {
            if (screen.GetPixel(i, posY) == ColorsInRow[0])
            {
                if (IsFarmable(posY, ColorsInRow, i, screen))
                {
                    partOfMainTable.Add(i, 1);
                }
            }
            else if (IsBackground(BackgroundColors, i, posY, screen))
            {
                partOfMainTable.Add(i, 0);
            }
            else
            {
                partOfMainTable.Add(i, 2);                
            }
        }
        return partOfMainTable;
    }

XAxysScan 関数に入った直後にロックを解除していることをどのように確認できますか。

4

1 に答える 1

2

XAxysScan 関数に入った直後にロックを解除していることをどのように確認できますか。

ReaderWriterLockSlim、複数のスレッドがリソースから読み取ることを許可する同期オブジェクトですが、(理想的には) 1 つのリソースにのみ書き込みを許可します。

これが重要な理由は、ReaderWriterLockSlimこの効果を達成するために実装される特定の方法にはManaged Thread Affinityと呼ばれるものが必要だからです。これは基本的に、を呼び出したスレッドが同じであるか、 を呼び出すスレッドでTaskあるEnterReadLock()必要があることを意味します。 TaskExitReadLock();

以下を見るとRunTasks(ScreenScanning ss)、ロックに入ったことがわかりますが、すぐに新しい子を開始し、 への参照としてTaskを渡します。ReaderWriterLockSlimXAxysScan()

ScreenLocker.EnterReadLock();
var t = new Task(() =>
{
    PosXOfBlocksAndMeaningOfIt.Add(ss.XAxysScan(PosYOfRowsToScan[i], Screen, ref ScreenLocker));
});

Taskロックを解除できるのは、ロックに入ったものだけです。少なくともそのような同期オブジェクトでは、 Managed Thread AffinityReaderWriterLockSlimを使用します。

メソッドEnterReadLock()への移行を検討してください。XAxysScan()

public Dictionary<int, int> XAxysScan(int posY, Bitmap screen, ref ReaderWriterLockSlim screenLocker)
{
    screenLocker.EnterReadLock();
    try{
        Dictionary<int, int> partOfMainTable = new Dictionary<int, int>();
    partOfMainTable.Add(666, posY); //used in BotViewUpdate in DataToTableInterpreter
        for (int i = 0; i <= 1920; i++)
        {
            if (screen.GetPixel(i, posY) == ColorsInRow[0])
            {
                if (IsFarmable(posY, ColorsInRow, i, screen))
                {
                    partOfMainTable.Add(i, 1);
                }
            }
            else if (IsBackground(BackgroundColors, i, posY, screen))
            {
                partOfMainTable.Add(i, 0);
            }
            else
            {
                partOfMainTable.Add(i, 2);                
            }
        }
        return partOfMainTable;
    }
    finally
    {
        // make sure that even if we encounter an error, we still exit the lock so other threads can enter the lock / begin writing
        screenLocker.ExitReadLock();
    }
于 2021-05-16T18:52:29.703 に答える