lock
uses this pattern
if(Monitor.Enter(lock))
try
{
...
}
finally { Monitor.Exit(lock); } // using this style to reduce post "height"
if we don't want to wait infinite we can provide timeout
if(!Monitor.TryEnter(lock, timeout))
throw new TimeoutException();
try
{
...
}
finally { Monitor.Exit(lock); }
I have scenario when method has to obtain multiple locks before it start doing anything. This looks awful:
if(!Monitor.TryEnter(lockA, timeout))
throw new TimeoutException();
try
{
if(!Monitor.TryEnter(lockB, timeout))
throw new TimeoutException();
try
{
if(!Monitor.TryEnter(lockC, timeout))
throw new TimeoutException();
try
{
... // more of such constructions
}
finally { Monitor.Exit(lockC); }
}
finally { Monitor.Exit(lockB); }
}
finally { Monitor.Exit(lockA); }
It has problems:
looks ugly (the method code is indented, imagine how it will looks for lockZ
), can be solved by putting method code into another method.
locking occurs synchronously, so the worst successful case may take time slightly less than a sum of all timeouts.
Is there a way to improve this timeout pattern?
I was thinking to make a method with delegate parameter and lock to achieve something like linq chaining (but to also run locks in parallel, this is a challenge):
Lock(lockA).Lock(lockB).Lock(lockC).Run( () => ...);
Or perhaps there is another way?
You can use the database system monitor to help you track the number of times an application (connection) experienced a lock timeout or that a database detected a timeout situation for all applications that were connected. Too low a value for this configuration parameter. An application (transaction) that is holding locks for an extended period.
Semaphore pattern implementation with timeout of lock/unlock operations. ? The semaphore provides API to control access to a shared resource by multiple goroutines or limit throughput. releaser, err := semaphore. Acquire ( breaker. BreakByTimeout ( time. Second )) if err != nil { // timeout exceeded } defer releaser. Release ()
This parameter specifies the number of seconds that an application will wait to obtain a lock, helping avoid global deadlocks for applications. If you set this parameter to 0 , locks are not waited for.
Timeout Pattern is one of the simplest Microservice Design Patterns for designing resilient Microservices. Introducing timeout solves the network related issues partially. Not fully.
I would go with usings for sync lock:
using System;
using System.Threading;
public class MyLock : IDisposable
{
private object lockObj;
public MyLock(object lockObj, TimeSpan timeout)
{
this.lockObj = lockObj;
if (!Monitor.TryEnter(this.lockObj, timeout))
throw new TimeoutException();
}
public void Dispose()
{
Monitor.Exit(lockObj);
}
}
Usage:
using(new MyLock(lockA, new TimeSpan.FromSeconds(1)))
using(new MyLock(lockB, new TimeSpan.FromSeconds(2)))
using(new MyLock(lockC, new TimeSpan.FromSeconds(3)))
{
// your code
}
Do not know if "locking" in ctor is good pattern / design, but it will work ;)
For async. parallelization is not good idea. Why?
If some thread will enter the monitor, the same thread must leave it (exit with lock). So if you lock on objA
within Parallel.ForEach
(f.e.) you will not know which thread has done it. So you won't be able to release it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With