多线程函数中的 LockRecursionException
LockRecursionException in multiple threaded function
我不知道如何描述它,但我得到一个例外,当代码写得很好时,应该没有位置。这个异常是关于 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函数后马上就释放了锁
How can you see I'm releasing lock right after entering XAxysScan function.
ReaderWriterLockSlim
is a synchronization object允许多个线程从资源读取,但只允许 1 个资源写入(理想情况下)。
这很重要的原因是因为 ReaderWriterLockSlim
实现这种效果的具体方法需要称为 Managed Thread Affinity 的东西,这基本上意味着无论 Task
还是 Thread调用 EnterReadLock()
的必须是 same Task
或调用 ExitReadLock();
.
的线程
当我们看下面的时候,我们可以看到你已经RunTasks(ScreenScanning ss)
进入了锁,但是你马上开始了一个新的child Task
并且通过了ReaderWriterLockSlim
作为对 XAxysScan()
.
的参考
ScreenLocker.EnterReadLock();
var t = new Task(() =>
{
PosXOfBlocksAndMeaningOfIt.Add(ss.XAxysScan(PosYOfRowsToScan[i], Screen, ref ScreenLocker));
});
只有进入锁的 Task
才能释放锁。至少对于使用 Managed Thread Affinity.
的 ReaderWriterLockSlim
之类的同步 objects
考虑将 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();
}
我不知道如何描述它,但我得到一个例外,当代码写得很好时,应该没有位置。这个异常是关于 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函数后马上就释放了锁
How can you see I'm releasing lock right after entering XAxysScan function.
ReaderWriterLockSlim
is a synchronization object允许多个线程从资源读取,但只允许 1 个资源写入(理想情况下)。
这很重要的原因是因为 ReaderWriterLockSlim
实现这种效果的具体方法需要称为 Managed Thread Affinity 的东西,这基本上意味着无论 Task
还是 Thread调用 EnterReadLock()
的必须是 same Task
或调用 ExitReadLock();
.
当我们看下面的时候,我们可以看到你已经RunTasks(ScreenScanning ss)
进入了锁,但是你马上开始了一个新的child Task
并且通过了ReaderWriterLockSlim
作为对 XAxysScan()
.
ScreenLocker.EnterReadLock();
var t = new Task(() =>
{
PosXOfBlocksAndMeaningOfIt.Add(ss.XAxysScan(PosYOfRowsToScan[i], Screen, ref ScreenLocker));
});
只有进入锁的 Task
才能释放锁。至少对于使用 Managed Thread Affinity.
ReaderWriterLockSlim
之类的同步 objects
考虑将 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();
}