C# multithreaded code access to local variables inside a lock

余生长醉 提交于 2019-12-13 07:07:03

问题


My question has to do with the following bit of code. I simplified the code to distill the question.

I understand that the lock keeps the foo Hashtable variable from being changed, but what about the variable outside the lock? We're seeing some odd behavior in code that looks like this and this was the question that came up. Thanks for any input.

using System.Collections;

namespace MultithreadScratch01
{
    public class ThreadFoo
    {
        public void Foo(Stub2 stub2, Hashtable foo)
        {
            Stub1 bar;

            var prop1 = stub2.Prop1;
            var prop2 = stub2.Prop2;
            var prop3 = stub2.Prop3;

            var hash = string.Format("{0}_{1}_{2}", prop1, prop2, prop3);

            lock(foo)
            {
                if(!foo.Contains(hash))
                {
                    bar = new Stub1 {Foo = "some arbitrary string", Bar = 123};
                    foo.Add(hash, bar);
                }
            }

        }
        public class Stub1
        {
            public string Foo { get; set; }
            public int Bar { get; set; }
        }
        public class Stub2
        {
            public string Prop1 { get; set; }
            public string Prop2 { get; set; }
            public string Prop3 { get; set; }

        }
    }
}

回答1:


What you're doing here is a "worst practice" in multiple ways.

First off, there is no guarantee whatsoever that other threads that have reference to that hash table are also locking it before they read or write it. That's why this technique is so bad; it is difficult to make that guarantee.

Second, there is no guarantee whatsoever that other threads that have reference to that hash table instance are not locking it and failing to unlock it because they are buggy or hostile. You are potentially putting other people in charge of the correctness of your code, and that is a dangerous position to be in. A good rule is "never lock anything that external code can see". Never lock "this", never lock a Type object, and so on. There are times to make an exception to that rule, but I would want a good reason.

The right thing to do here is to use a ConcurrentDictionary in the first place. If you can't do that, then I would write a wrapper around HashTable:

sealed class ThreadSafeHashTable
{
    private readonly HashTable hashTable = new HashTable();
    public void Add(object key, object value)
    {
        lock(this.hashTable)
        {
            ...

Now the locking is (1) always done every time Add is called, and (2) only the code in this class can possibly take the lock, because the object that is locked is private and never passed out.

Only if you could not do either of those things would I do this the hard way. If you want to do it the hard way then you are going to have to track down every single place the hash table could possibly be used and ensure that the correct locking code is written.




回答2:


It isn't quite true to say that the lock

keeps the foo Hashtable variable from being changed

simply; no two threads locking on the same object can be inside the lock at the same time. If you have any code that doesn't lock on the same object (the hash-table), it will walk right in and could well cause damage. Re the other variables... if anything is mutating the objects, and isn't locking on the same lock object that you are, things could get funky. Actually, there are even some edge-cases if it is locking on the same object (that would be solved my moving the property-reads inside the lock). However, since those variables aren't "captured", once you have a snapshot of the values the snapshot will not change.




回答3:


You are somewhat mistaken on what the lock is doing. It is not preventing other threads from accessing or modifying foo, but it is actually preventing other threads from entering the code block the lock surrounds. If you are modifying foo elsewhere, you might see issues.

Since hash is a local variable, you shouldn't see any problems with it.

You might want to try using a ConcurrentDictionary instead of a Hashtable, it is designed for multi-threaded access.




回答4:


Locking on a parameter is a dangerous game as the guys above have alluded to since you don't know what is being done with that parameter outside of your method. Someone else could be modifying it at the same time.

You could wrap all the code in your method to make sure only one thread is in that code at a time, but since your Stub1 and Stub2 classes aren't thread safe (need to put locks on the properties) then even doing that wouldn't guarantee that the properties aren't being changed while you're reading them.



来源:https://stackoverflow.com/questions/9704128/c-sharp-multithreaded-code-access-to-local-variables-inside-a-lock

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!