Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does lock(){} lock a resource, or does it lock a piece of code?

I'm still confused... When we write some thing like this:

Object o = new Object();
var resource = new Dictionary<int , SomeclassReference>();

...and have two blocks of code that lock o while accessing resource...

//Code one
lock(o)
{
  // read from resource    
}

//Code two
lock(o)
{
  // write to resource
}

Now, if i have two threads, with one thread executing code which reads from resource and another writing to it, i would want to lock resource such that when it is being read, the writer would have to wait (and vice versa - if it is being written to, readers would have to wait). Will the lock construct help me? ...or should i use something else?

(I'm using Dictionary for the purposes of this example, but could be anything)

There are two cases I'm specifically concerned about:

  1. two threads trying to execute same line of code
  2. two threads trying to work on the same resource

Will lock help in both conditions?

like image 854
Prerak K Avatar asked Apr 15 '09 18:04

Prerak K


People also ask

What does lock lock () do?

The lock() method is one of the most important methods of the Lock interface. It is used for acquiring the lock. For thread scheduling purposes, the current thread becomes disabled when the lock is not available. The lock() method is a public method that returns void.

What is resource lock?

The process of protecting the data in a database in a multiprocessing environment.

What is a lock in code?

A code that prevents a wireless phone from unauthorized use. When explicitly locked, and each time the phone is turned on, it will prompt the user to enter the code before it will allow a call to be placed.

What does lock () return when a the lock is being held?

While a lock is held, the thread that holds the lock can again acquire and release the lock. Any other thread is blocked from acquiring the lock and waits until the lock is released. Since the code uses a try... finally block, the lock is released even if an exception is thrown within the body of a lock statement.


2 Answers

Most of the other answers address your code example, so I'll try to answer you question in the title.

A lock is really just a token. Whoever has the token may take the stage so to speak. Thus the object you're locking on doesn't have an explicit connection to the resource you're trying to synchronize around. As long as all readers/writers agree on the same token it can be anything.

When trying to lock on an object (i.e. by calling Monitor.Enter on an object) the runtime checks if the lock is already held by a thread. If this is the case the thread trying to lock is suspended, otherwise it acquires the lock and proceeds to execute.

When a thread holding a lock exits the lock scope (i.e. calls Monitor.Exit), the lock is released and any waiting threads may now acquire the lock.

Finally a couple of things to keep in mind regarding locks:

  • Lock as long as you need to, but no longer.
  • If you use Monitor.Enter/Exit instead of the lock keyword, be sure to place the call to Exit in a finally block so the lock is released even in the case of an exception.
  • Exposing the object to lock on makes it harder to get an overview of who is locking and when. Ideally synchronized operations should be encapsulated.
like image 198
Brian Rasmussen Avatar answered Oct 13 '22 22:10

Brian Rasmussen


Yes, using a lock is the right way to go. You can lock on any object, but as mentioned in other answers, locking on your resource itself is probably the easiest and safest.

However, you may want use a read/write lock pair instead of just a single lock, to decrease concurrency overhead.

The rationale for that is that if you have only one thread writing, but several threads reading, you do not want a read operation to block an other read operation, but only a read block a write or vice-versa.

Now, I am more a java guy, so you will have to change the syntax and dig up some doc to apply that in C#, but rw-locks are part of the standard concurrency package in Java, so you could write something like:

public class ThreadSafeResource<T> implements Resource<T> {
    private final Lock rlock;
    private final Lock wlock;
    private final Resource res;

    public ThreadSafeResource(Resource<T> res) {
        this.res = res;
        ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
        this.rlock = rwl.readLock();
        this.wlock = rwl.writeLock();
    }

    public T read() {
        rlock.lock();
        try { return res.read(); }
        finally { rlock.unlock(); }
    }

    public T write(T t) {
        wlock.lock();
        try { return res.write(t); }
        finally { wlock.unlock(); }
    }
}

If someone can come up with a C# code sample...

like image 40
Varkhan Avatar answered Oct 13 '22 21:10

Varkhan