views:

236

answers:

4

Hi all,

I want to make multiple instances of this class.

public class Worker
{
    private object _lockObject;
    private Thread _workerThread;
    private string _name;

    public Worker(object lockObject, string name)
    {
        _name = name;
        _lockObject = lockObject;
        _workerThread = new Thread(new ThreadStart(DoWork));
        _workerThread.Start();
    }
    private void DoWork()
    {
        while(true)
        {
            lock(_lockObject)
            {
                Console.WriteLine(_name + "Doing Work");
            }
        }
    }
}

If I pass the same lock object to multiple instances of the class, will a lock in one class instance result in the other class instance waiting on that lock to be free?

static void Main()
{
    private readonly object sharedLockObject = new object();
    Worker a = new Worker(sharedLockObject,"a");
    Worker b = new Worker(sharedLockObject,"b");
    Console.ReadLine();
}

I think that in the above case, Workers will never be : Console.WriteLine(_name + "Doing Work"); at the same time?

I just would like some confirmation, as I am unsure as to whether the lock() will lock the reference, or the object that is referenced.

Thanks!

+7  A: 

Yes, object is a reference type so you are passing a reference to the same object, so that same object would be used by each Worker. The object is used for locking, not the reference.

GraemeF
thanks "The object is used for locking, not the reference" would love to find that in the C# spec
divinci
"The lock statement obtains the mutual-exclusion lock for a given object" - http://msdn.microsoft.com/en-us/library/aa664735(VS.71).aspx
GraemeF
+4  A: 

The lock statement will mark the object instance, not the referencing variable.

lock(x) {
   ...
}

Is precisely equivalent to:

System.Threading.Monitor.Enter(x);
try {
   ...
}
finally {
   System.Threading.Monitor.Exit(x);
}

where x is an object instance of a reference type.

So yes :-)

Yannick M.
+2  A: 

I would recommend you not to pass a shared object that you use for locking or you could get into some nasty deadlocks. Use a static private member of the class to lock on:

public class Worker
{
    private static object _syncRoot = new object();
    private Thread _workerThread;
    private string _name;

    public Worker(string name)
    {
        _name = name;
        _workerThread = new Thread(new ThreadStart(DoWork));
        _workerThread.Start();
    }
    private void DoWork()
    {
        while(true)
        {
            lock(_syncRoot)
            {
                Console.WriteLine(_name + "Doing Work");
            }
        }
    }
}
Darin Dimitrov
Unless he also needs to synchronize access to the same shared memory from other locations in the code besides the multiple instances of tghis class...
Charles Bretana
I partly agree with you, in that if it's a critical section, it might be critical over all instances. But then again it might not, and only apply to this object instance, which would make his implementation perfectly fine.
Yannick M.
@Charles Bretana: If one needs to synchronize access to the same shared memory from multiple locations in the code, it would be a better design to wrap a class around that shared memory and provide synchronized access to it through the class' public interface. I agree with Darin, here. Passing a sync object around like this will become problematic as the code base gets larger.
Matt Davis
@Matt, if your proposed class logically represented the functionality that each of those multiple locations was implemnting, then I would indeed take that approach, but if the functionality that needs access to that shared memory is logically part of several disparate classes according to the systems high level domain architectural design pattern, I would not violate that pattern just to put the locker in the same class as the code that needs it.
Charles Bretana
+2  A: 

What you are doing will work, but why not make the _lockObject member of the Worker class static? It will achieve the same effect but is more object-oriented.

public class Worker
{
    private static object _lockObject = new object();
    private Thread _workerThread;
    private string _name;

    public Worker(string name)
    {
        _name = name;
        _workerThread = new Thread(new ThreadStart(DoWork));
        _workerThread.Start();
    }
    private void DoWork()
    {
        while(true)
        {
            lock(_lockObject)
            {
                Console.WriteLine(_name + "Doing Work");
            }
        }
    }
}

EDIT: Oops! I didn't see @Darin Dimitrov's response, which is identical to what I've posted here. +1 to you, Darin.

Matt Davis