Conditionally Use Lock in the Thread? - c#

I have a method which is being used by multi-thread. In the method, there are some critical codes that I have to use lock to allow only ONE thread to access it. So, the code looks like:
private void RunCode()
{
...... // some other codes
lock (myLock)
{
...... // critical code01
}
...... // some other codes
lock (myLock)
{
...... // critical code02
}
....... // some other codes
}
This code is being used by multi-thread. Now, because of some workflow changes, we want to keep the code run as it is, BUT in some special cases, we want to run the critical codes immediately without the lock. We are ok even if the calculation result is not 100% correct because we do not lock it. So, the code should look like:
private void RunCode(bool isSpecial)
{
...... // some other codes
lock (myLock) // if isSpecial == true, do not lock it, otherwise, lock it
{
...... // critical code01
}
...... // some other codes
lock (myLock) // if isSpecial == true, do not lock it, otherwise, lock it
{
...... // critical code02
}
....... // some other codes
}
Based on research, it seems we have to do something like
if (isSpecial)
{
...... // critical code01
}
else
{
lock (myLock)
{
...... // critical code01
}
}
It will work, but the issue is that we have to repeat the critical code01 (and code02) twice. And these codes are pretty complex and closely related with other codes in the RunCode() method.
My question is: is there a better way to do this? Any suggestions? We are using c# .net, but any suggestions are welcome.
Thanks

Try use a Monitor class directly. It has a method TryEnter
Rewrite your code like this:
try
{
if (isSpecialCase || Monitor.TryEnter(myLock, TimeSpan.MaxValue))
{
// critical code01
}
}
finally
{
if (!isSpecialCase)
{
// lock was taken
Monitor.Exit(myLock);
}
}

What you want to do sounds pretty strange to say the least. But if I could not live without it, I would try defining a lambda expression on the fly and call that in these two locations. Something along the lines of
int aNumber = 5;
Action criticalCode01 = () => {Console.WriteLine("Foo! (repeat "+aNumber+" times)");};
if (isSpecial)
{
criticalCode01();
}
else
{
lock (myLock)
{
criticalCode01();
}
}

This is what you are looking for:
try
{
if (!isSpecialCase) Monitor.Enter(myLock);
// critical code01
}
finally
{
if (!isSpecialCase) Monitor.Exit(myLock);
}

Related

implementing a c# read write lock where some reads produce writes

I have to implement some .Net code involving a shared resource accessed by different threads. In principle, this should be solved with a simple read write lock. However, my solution requires that some of the read accessions do end up producing a write operation. I first checked the ReaderWriterLockSlim, but by itself it does not solve the problem, because it requires that I know in advance if a read operation can turn into a write operation, and this is not my case. I finally opted by simply using a ReaderWriterLockSlim, and when the read operation "detects" that needs to do a write operation, release the read lock and acquire a write lock. I am not sure if there is a better solution, or event if this solution could lead to some synchronization issue (I have experience with Java, but I am fairly new to .Net).
Below some sample code illustrating my solution:
public class MyClass
{
private int[] data;
private readonly ReaderWriterLockSlim syncLock = new ReaderWriterLockSlim();
public void modifyData()
{
try
{
syncLock.EnterWriteLock();
// clear my array and read from database...
}
finally
{
syncLock.ExitWriteLock();
}
}
public int readData(int index)
{
try
{
syncLock.EnterReadLock();
// some initial preprocessing of the arguments
try
{
_syncLock.ExitReadLock();
_syncLock.EnterWriteLock();
// check if a write is needed <--- this operation is fast, and, in most cases, the result will be false
// if true, perform the write operation
}
finally
{
_syncLock.ExitWriteLock();
_syncLock.EnterReadLock();
}
return data[index];
}
finally
{
syncLock.ExitReadLock();
}
}
}

Optional thread safety (thread safe section only under condition)

As stated in the title i have this situation
lock ( _myLockObj )
{
// protected section here ( select + update over SQL Tables)
}
That works great , but sometimes i do not need thread safety , because is guaranteed by datas that nothing wrong could happen (even if two thread run in parralel) but i need speed .
At the moment program can understand when threads could have threads safety problem and when not ( and when not i need to be fast as possible ) .
What i would achieve make is optionallity on that lock instruction , so that it become effective only if in proper condition is true .
eg :
lock ( _myLockObj ) && flag
I am pretty sure that lock keyword does not provide that semantics, what i would understand is what is the proper way to achieve that behavior.
The lock statement is a syntactic sugar for Monitor.Enter + Monitor.Exit in a try/finally block.
You can use these methods directly:
bool flag = false;
bool acquiredLock = false;
try
{
if (flag)
{
Monitor.Enter(_myLockObj, ref acquiredLock);
}
}
finally
{
if (flag & acquiredLock)
{
Monitor.Exit(_myLockObj);
}
}
Personally I think the following is nicer:
private bool flag;
public T DoStuff() {
T DoStuffUnsafe() {
// ...
}
if (flag) {
lock (_myLockObj) {
return DoStuffUnsafe();
}
}
else {
return DoStuffUnsafe();
}
}

Try in finally block

try
{
operation1();
operation2();
...
}
finally
{
try
{
finalizer_operation1();
finalizer_operation2();
}
finally
{
very_critical_finalizer_operation_which_should_occurs_at_the_end();
}
}
Is this ok? To have finalizer as another try/finally block (because finalizer_operationX() may throw and I must ensure that very_critical...() will happens at the end.
Quick googling for try in finally block brings nothing (will delete question if you give me a duplicate link), it should work, but I am unsure in design and possible problems with it.
I would not write the code this way. I don't like nesting try/catch/finally constructs. I prefer one per method.
My preference is to wrap each of those calls in its own method.
try
{
operation1();
operation2();
...
}
finally
{
cleanup();
}
public void cleanup() {
try
{
finalizer_operation1();
finalizer_operation2();
}
finally
{
very_critical_finalizer_operation_which_should_occurs_at_the_end();
}
}
Of course it is. A finally block will execute if control flow enters the corresponding try block.
The only exception is a call that shuts down the VM.

Monitor.TryEnter / Monitor.Exit and SynchronizationLockException

Is it possible to detect if the same thread trying to release the lock?
We have many places in code that looks like:
try
{
try
{
if(!Monitor.TryEnter(obj, 2000))
{
throw new Exception("can not lock");
}
}
finally
{
Monitor.Exit(obj);
}
}
catch
{
//Log
}
The above code very simplified, and actually Enter and Exit statement located in custom object (lock manager).
The problem, that in that structure, we have SynchronizationLockException when trying to "Exit", since it looks like the thread that not succeed to lock, tries to release in finally.
So the question, is how I can know if the thread who making Monitor.Exit is the same thread who did Monitor.Enter?
I thought that I can use CurrentThread.Id to sync enter and exit, but I'm not sure if it "safe" enough.
So the question, is how I can know if the thread who making Monitor.Exit is the same thread who did Monitor.Enter?
You can't, easily, as far as I'm aware. You can't find out which thread owns a monitor.
However, this is just a coding issue - you should change your code so that it doesn't even attempt to release the monitor when it shouldn't. So your code above could be rewritten as:
if (!Monitor.TryEnter(obj, 2000))
{
throw new Exception(...);
}
try
{
// Presumably other code
}
finally
{
Monitor.Exit(obj);
}
Or even better, if you're using .NET 4, use the overload of TryEnter which accepts an ret parameter:
bool gotMonitor = false;
try
{
Monitor.TryEnter(obj, ref gotMonitor);
if (!gotMonitor)
{
throw new Exception(...);
}
// Presumably other code
}
finally
{
if (gotMonitor)
{
Monitor.Exit(obj);
}
}
As you think that to put the calling of Monitor.Exit in try-catch was 'durty'(dirty?), here's a very simple idea trying to 'take the durty away'. Lock is reentrant for the same thread and if one thread acquired successfully, before it releases, attempt from another thread will fail. So that you can consider something like:
public void Exit(object key) {
if(!IsActive) {
return;
}
if(LockDictionary.ContainsKey(key)) {
var syncObject=LockDictionary[key];
if(Monitor.TryEnter(syncObject.SyncObject, 0)) {
SetLockExit(syncObject);
Monitor.Exit(syncObject.SyncObject);
Monitor.Exit(syncObject.SyncObject);
}
}
}
We call Monitor.Exit twice because we lock it twice, one in the code outer, and one just here.
I know this is an older question, but here's my answer anyway.
I would move the try-finally construct inside the if:
try
{
if(Monitor.TryEnter(obj, 2000))
{
try
{
// code here
}
finally
{
Monitor.Exit(obj);
}
}
else
{
throw new Exception("Can't acquire lock");
}
}
catch
{
// log
}

How do i stop the The database file is locked exception?

I have a multithreaded app that uses sqlite. When two threads try to update the db at once i get the exception
Additional information: The database file is locked
I thought it would retry in a few milliseconds. My querys arent complex. The most complex one (which happens frequently) is update, select, run trivial code update/delete, commit. Why does it throw the exception? How can i make it retry a few times before throwing an exception?
SQLite isn't thread safe for access, which is why you get this error message.
You should synchronize the access to the database (create an object, and "lock" it) whenever you go to update. This will cause the second thread to block and wait until the first thread's update finishes automatically.
try to make your transaction / commit blocks as short as possible. The only time you can deadlock/block is with a transaction -- thus if you don't do them you won't have the problem.
That said, there are times when you need to do transactions (mostly on data updates), but don't do them while you are "run trivial code" if you can avoid it.
A better approach may be to use an update queue, if you can do the database updates out of line with the rest of your code. For example, you could do something like:
m_updateQueue.Add(()=>InsertOrder(o));
Then you could have a dedicated update thread that processed the queue.
That code would look similar to this (I haven't compiled or tested it):
class UpdateQueue : IDisposable
{
private object m_lockObj;
private Queue<Action> m_queue;
private volatile bool m_shutdown;
private Thread m_thread;
public UpdateQueue()
{
m_lockObj = new Object();
m_queue = new Queue<Action>();
m_thread = new Thread(ThreadLoop);
m_thread.Start();
}
public void Add(Action a)
{
lock(m_lockObj)
{
m_queue.Enqueue(a);
Monitor.Pulse(m_lockObj);
}
}
public void Dispose()
{
if (m_thread != null)
{
m_shutdown = true;
Monitor.PulseAll(m_lockObj);
m_thread.Join();
m_thread = null;
}
}
private void ThreadLoop()
{
while (! m_shutdown)
{
Action a;
lock (m_lockObj)
{
if (m_queue.Count == 0)
{
Monitor.Wait(m_lockObj);
}
if (m_shutdown)
{
return;
}
a = m_queuue.Dequeue();
}
a();
}
}
}
Or, you could use something other than Sql Lite.

Categories

Resources