Reputation: 414
I have a resource shared between several threads and the following usage pattern:
Thread 1 uses protected resource constantly.
Threads 2..N need to interact with protected resource infrequently and for a very short amounts of time.
I want thread 1 to hold the lock protecting the resource constantly and at specific times in it's work cycle yield to other threads waiting for their turn. If no other threads happen to be waiting, it should reacquire the lock immediately and continue its' work.
I guess one way to do it is this:
lock (resource)
{
while (!stop)
{
resource.DoWorkIteration();
// give other threads a chance
Monitor.Exit(resource);
Thread.Sleep(0);
Monitor.Enter(resource);
}
}
However Sleep(0) will yield to any ready to run thread, not just to the ones waiting for this particular resource.
Is there a better way to do it, that avoids unnecessary yielding?
Upvotes: 0
Views: 43
Reputation: 17415
It's a general advise, but instead of competing for a resource, you should coordinate access to it. The reason is that the overhead of locking, unlocking and context switching isn't negligible and further that it always presents the danger of deadlocks. Releasing and reacquiring a lock isn't for free either, so you'd best avoid it.
In your case, I would suggest that whatever thread 2..N need to get done with the resource is actually done by thread 1 instead. For that, use callbacks stored in a queue (preferably one that operates non-blocking). When the queue is empty, thread 1 does its own thing, otherwise it pops a callback off the queue and executes it. If you need a result, use an event that the requesting thread waits for. Maybe you can also leverage the existing system that .Net uses to delegate calls from non-UI threads to UI elements.
Upvotes: 2