Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Locking on an object

Tags:

c#

locking

I often see code like that which is shown here, ie where an object is allocated and then used as a "lock object".

It seems to me that you could use any object for this, including the event itself as the lock object. Why allocate a new object that does nothing? My understanding is that calling lock() on an object doesn't actually alter the object itself, nor does it actually lock it from being used, it's simply used as a placeholder for multiple lock statements to anchor on.

public class Shape : IDrawingObject, IShape
{
    // Create an event for each interface event
    event EventHandler PreDrawEvent;
    event EventHandler PostDrawEvent;

    object objectLock = new Object();

    // Explicit interface implementation required.
    // Associate IDrawingObject's event with
    // PreDrawEvent
    event EventHandler IDrawingObject.OnDraw
    {
        add
        {
            lock (objectLock)
            {
                PreDrawEvent += value;
            }
        }
        remove
        {
            lock (objectLock)
            {
                PreDrawEvent -= value;
            }
        }
    }
}

So my question is, is this really a good thing to do?

like image 636
Erik Funkenbusch Avatar asked Jun 05 '10 06:06

Erik Funkenbusch


People also ask

What do you mean by locking objects?

Object Lock can help prevent objects from being deleted or overwritten for a fixed amount of time or indefinitely. You can use Object Lock to help meet regulatory requirements that require WORM storage, or to simply add another layer of protection against object changes and deletion.

How do you lock an object?

In Object Designer, select one or more objects that are not already locked, and then do one of the following steps: Right-click the object or objects, and then choose Lock. On the File menu, choose Lock. Press Ctrl+Alt+L.

What is object lock in Java?

An object-level lock is a mechanism when we want to synchronize a non-static method or non-static code block such that only one thread will be able to execute the code block on a given instance of the class. If a thread wants to execute a synchronized method on the given object.

What are different types of lock objects?

There are two types of lock objects are available, DEQUEE, ENQUEE. Type of locks: Exclusive Lock: The locked data can be read or processed by one user only. Shared Lock: Several users can read the same data at the same time, but as soon as a user edits the data, a second user can no longer access this data.


2 Answers

including the event itself

No, you can't do that. An "event" is actually just some accessor methods. Assuming you mean the backing delegate, that would be very bad - delegates are immutable: every time you add/remove a subscriber, you get a different delegate.

Actually, the 4.0 compiler now does this with lock-free code using Interlocked - it may be worth following this approach instead.

In your example, the objectLock ensures that all callers (to that instance) are locking against the same object, which is important - but without the ugliness of locking on this (which is how the C# compiler used to work).

--

Update: your example shows code that is necessary before C# 4.0, access to a field-like-event inside the type talked directly to the field: the normal field-like-event locking was not respected. This was changed in C# 4.0; you can now (in C# 4.0) safely re-write this as:

public class Shape : IDrawingObject, IShape
{
    // Create an event for each interface event
    event EventHandler PreDrawEvent;
    event EventHandler PostDrawEvent;

    event EventHandler IDrawingObject.OnDraw
    {
        add { PreDrawEvent += value; }
        remove { PreDrawEvent -= value; }
    }
}

All the correct behaviour is then followed.

like image 163
Marc Gravell Avatar answered Oct 16 '22 03:10

Marc Gravell


Any private reference type member will do the job. As long as it is private and never gets reassigned. Which knocks a delegate object out of the running, you definitely don't want to see a lock fail to do its job simply because client code that you don't control assigns an event handler. Extremely hard to debug.

Using private members that do another job is not something that scales well. If you find out you need to lock another region of code while refactoring or debugging, you'll need to find another private member. Which is where things can turn sour quickly: you might pick the same private member again. Deadlock knocking on the door.

This doesn't happen if you dedicate a lock object to a specific set of shared variables that need to be protected. Allows you to give it a good name too.

like image 22
Hans Passant Avatar answered Oct 16 '22 03:10

Hans Passant