This is the ninth part of the Concurrency series. For your convenience you can find other parts in the table of contents in Part 1 – Mutex performance in .NET
Last time we implemented custom mutex based on memory mapped files. We can use it to track who owns the lock in much simpler way. Today we will implement a counting semaphore.
Idea is simple: we want to create multiple mutexes, iterate through all of them and choose first available. If none is free, we just choose one and wait on it for a little longer. This is very dirty implementation and can lead to starvation, though.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public static void DoWithSemaphore(string name, int semaphoresCount, Action action) { bool checkedAll = false; string fullName; for (int index = 0; ; index = (index + 1) % semaphoresCount) { fullName = name + index; if (DoWithMutex(fullName, action, checkedAll ? 20 : 1)) { break; } if (index == semaphoresCount - 1) { checkedAll = true; } } } |
So we accept number of semaphores (each of them being a binary semaphore) and we try to implement naive WaitAny
. This is obviously less than optimal and doesn’t work every time, but in reasonable system should perform pretty well. Once again, your mileage may vary and I take no responsibility.