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
ReaderWriterLockSlim
is 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
ReaderWriterLockSlim
is implemented to achieve this effect, requires something called Managed Thread Affinity, which basically means that whateverTask
or Thread that called theEnterReadLock()
must be the sameTask
or 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 childTask
and pass theReaderWriterLockSlim
as a reference toXAxysScan()
.Only the same
Task
that enters a lock can be the one to release that lock. At least for synchronization objects likeReaderWriterLockSlim
that use Managed Thread Affinity.Consider moving
EnterReadLock()
into theXAxysScan()
method.