简体   繁体   中英

Does locking C# delegates for writing guarantee thread safety?

C# delegates are immutable, so when you add or remove a function from the delegate, it is replaced by a new object.

Considering the following piece of code:

lock(shared_instance.my_delegate){
  shared_instance.my_delegate+=Foo;
}

Consider the following situation:

Threads 1 and 2 arrive at the lock, thread 2 blocks on the delegate instance, let's call it A .

Thread 1 replaces A with a new instance, B , and exits the lock.

Does thread 2 acquire lock on B or on A ? If it's on A , then it seems to me that thread 3 could come along, acquire a lock on B at the same time when thread 2 acquires a lock on A , and they could simultaneously try to overwrite the deleage and a race would occur, correct?

EDIT:

I now realize that the question could be generalized to any reference type:

lock(shared_ref){
  shared_ref=different_ref;
}

Basically what I want to know is: If this happens, waiting threads will still lock on the old reference, yes?

Does thread 2 acquire lock on B or on A? If it's on A, then it seems to me that thread 3 could come along, acquire a lock on B at the same time when thread 2 acquires a lock on A, and they could simultaneously try to overwrite the deleage and a race would occur, correct?

You have a race condition in both cases. You have a race condition with your code, you have the race condition if you use a dedicated object to lock on, and you have the same race condition if you just have no lock at all. In all of the three cases one of the threads will set the value and have it immediately overridden, and one will set the value second and have it stick. In all of these cases it's indeterminate which thread will "win". In none of these cases will anything else happen besides the value being set to one of the two possible values.

looking at this code:

lock(shared_ref){
  shared_ref=different_ref;
}

lock(shared_ref) will lock the reference of what ever is inside the shared_ref variable, replacing the value of the variable will not change the lock and at the end of the lock { } block, the old reference will be released. So if any other thread locks on shared_ref before it is changed but while it is locked, the lock will still be released. A third thread might lock onto the new reference when it is already set and a race for the setting the variable would occur, because thread 2 will be release and thread 3 never waits at the lock because noone holds the reference. So thread 2 and 3 will race for setting the new variable

i just made some sample code, which i think makes it pretty clear:

public class TestClass
{
    public static object myObject;

    public static void setObject(object newValue, string thread)
    {
        lock(myObject)
        {
            Debug.Print(thread+" reached the inside of the lock");
            Thread.Sleep(1000);
            myObject = newValue;
            Debug.Print(thread + " myObject was set");
            Thread.Sleep(1000);
        }
        Debug.Print(thread + " lock released");
    }

    public static void Test()
    {
        myObject = new object();
        Thread t1 = new Thread(t1_run);
        Thread t2 = new Thread(t2_run);
        Thread t3 = new Thread(t3_run);
        t1.Start();
        t2.Start();
        t3.Start();
    }

    private static void t1_run()
    {
        setObject(new object(), "t1");
    }

    private static void t2_run()
    {
        Thread.Sleep(500); // 500 millisecods so it will be locked on the old
        setObject(new object(), "t2");
    }

    private static void t3_run()
    {
        Thread.Sleep(1500); // just make sure myObject was replaced
        setObject(new object(), "t3");
    }
}

now obviously the output is:

t1 reached the inside of the lock
t1 myObject was set
t3 reached the inside of the lock
t1 lock released
t2 reached the inside of the lock
t3 myObject was set
t2 myObject was set
t3 lock released
t2 lock released

because the sleeps ensure the order in which t2 and t3 set myObject. But that is not ensured when the timing is very close

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM