I dont know how to describe it but I'm getting exception that schouldn't have a place when a code is good written. This exception is about issue with ReaderWriterLockSlim and it's LockRecursionException; it is appearing at "ScreenLocker.EnterReadLock();" line. Can't find problem with my code and description what to do or what might be wrong at internet, that's why i writting this question here and asking you all for help. This is code I have problem with:
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;
}
and that are functions called by this method:
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;
}
How can you see I'm releaseing lock right after entering XAxysScan function.
The
ReaderWriterLockSlimis a synchronization object that allows multiple threads to read from a resource, but only allow 1 resource to write to it(ideally).The reason why this is important is because the specific way that
ReaderWriterLockSlimis implemented to achieve this effect, requires something called Managed Thread Affinity, which basically means that whateverTaskor Thread that called theEnterReadLock()must be the sameTaskor thread that callsExitReadLock();.When we look at the following, we can see you Have
RunTasks(ScreenScanning ss)enter the lock, but you immediately start a new childTaskand pass theReaderWriterLockSlimas a reference toXAxysScan().Only the same
Taskthat enters a lock can be the one to release that lock. At least for synchronization objects likeReaderWriterLockSlimthat use Managed Thread Affinity.Consider moving
EnterReadLock()into theXAxysScan()method.