I'm trying to understand some basic multitasking approaches and concepts like Thread/Task/Semaphore. I'm a bit confused about semaphore and it's waiting mechanism.
I have created an example program. Fiddle
What I want to do is executing BigLock()
function in a certain time as some TestFunction
s are running.
If there are some TestFunction
s are running at the time of calling BigLock()
function, it should allow them to finish but not allow new TestFunction
execution until BigLock()
finishes its job.
public class Program
{
public static void Main(string[] args)
{
TestClass test = new TestClass();
test.TestRunner();
Thread.Sleep(100000);
}
}
public class TestClass
{
List<SemaphoreSlim> semaphoreArray = new List<SemaphoreSlim>();
SemaphoreSlim locker = new SemaphoreSlim(1);
private async void TestFunction(int i)
{
SemaphoreSlim s = new SemaphoreSlim(1);
semaphoreArray.Add(s);
await locker.WaitAsync();
await s.WaitAsync();
Console.WriteLine("{0} starts waiting",Task.CurrentId);
Thread.Sleep(1000);
s.Release();
locker.Release();
Console.WriteLine("{0} finished and released semaphore",Task.CurrentId);
}
public void TestRunner()
{
Task.Run(() => Parallel.For(1, 10, (i, state) => TestFunction(i)));
Task.Run(()=>BigLock());
Parallel.For(1, 10, (i, state) => TestFunction(i));
}
private async void BigLock()
{
Console.WriteLine("Started waiting all semaphores");
await locker.WaitAsync();
Console.WriteLine("WE ARE IN");
WaitHandle[] waitHandles = semaphoreArray
.Select(x => x.AvailableWaitHandle).ToArray();
if(waitHandles.Count()>0){
WaitHandle.WaitAll(waitHandles);
}
Console.WriteLine("That's the end");
locker.Release();
}
}
I expected that, after completion of some of the TestFunction
executions, BigLock
continues running.
But the output was not as I expected.
Started waiting all semaphores
WE ARE IN
That's the end
1 starts waiting
1 finished and released semaphore
starts waiting
starts waiting
finished and released semaphore
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
I added some delay to call BigLock
function and run the program again.
public void TestRunner()
{
Task.Run(() => Parallel.For(1, 10, (i, state) => TestFunction(i)));
Thread.Sleep(300);
Task.Run(()=>BigLock());
Parallel.For(1, 10, (i, state) => TestFunction(i));
}
The output was
1 starts waiting
1 finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
Started waiting all semaphores
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
starts waiting
finished and released semaphore
WE ARE IN
That's the end
What I understood from the second output is locker SemaphoreSlim
started waiting after 2nd call of TestFunction
executed and 3rd execution was started (line 6)
After that line I expected BigLock
function would continue running after 3rd call of Test execution finished.
But it didn't run until all calls to TestFunction
had finished.
Is there a priority mechanism that should be considered for that kind of scenarios?