C# Lock (“string”) not working for dynamic argument?

醉酒当歌 提交于 2020-01-05 12:58:30

问题


I am using C# lock to block code execution. It is not working if we use dynamic string input in Lock.

public class ParameterClass
    {
        public string A = string.Empty;
        public Int64 B = 0;
    }

    class Program
    {
        static void Main(string[] args)
        {
            ParameterClass parm = new ParameterClass { A = "Test", B = 1 };
            Thread thread = new Thread(ThreadFun);
            thread.Start(parm);

            System.Threading.Thread.Sleep(2000);

            parm = new ParameterClass { A = "Test", B = 1 };
            ThreadFun(parm);
        }

        public static void ThreadFun(object para)
        {
            ParameterClass parameter = (ParameterClass)para;
            lock (parameter.B.ToString())
            {
                Console.WriteLine(DateTime.Now);
                System.Threading.Thread.Sleep(20000);
            }
        }
    } 

Here , I have put Thread.Sleep(20000) - 20 seconds inside Lock statement. my expected result is the code block should be locked based on parameter.B...

Can anyone help me to proceed?


回答1:


If you need to lock upon a string you can use string.Intern on the string. Doing this you lock on the string reference.

lock (string.Intern(parameter.B.ToString()))
{ ... }

But be aware what this allows, unlike traditional lock objects (private readonly object) this type of lock can used anywhere in the code, potentially causing synchronization issues or deadlocks.




回答2:


Your code locking is equivalent to following since ToString() normally create new string on every call:

 lock(new object()) { ... }

which clearly not going to prevent other threads to execute the same block of code due to locking on different object each time.

You want to lock on object that somehow relates to data accessed in the protected block. In your case it may be either para itself or other reference type value inside parameter (value type B can't be used) if it does not change during execution:

 lock(para)
 {....}

Note that recommended approach if to have special "locking" private object that used to protect access to the data via methods of the same class...

Sample of the class that protects access to 2 properties via lock:

public class ParameterClass
{   
    private object lockObject = new object();
    private string a = string.Empty;
    private Int64 b = 0;

    public SafeSet(string v, long number)
    {
        lock(lockObject) 
        {
             a = v;
             b = number;
        }
    }

    public string A
    {
        get { lock(lockObject)  { return a; } }
    }

    public long B
    {
        get { lock(lockObject)  { return b; } }
    }
}



回答3:


Yes, locks works based on the reference not values. When you have two dynamically generated string they are different instances which means different references and hence it doesn't work.

If you use constant strings it will work properly since compile time strings are interned but it is a bad idea to use strings in lock.

  • lock (this) is a problem if the instance can be accessed publicly.

  • lock (typeof (MyType)) is a problem if MyType is publicly accessible.

  • lock("myLock") is a problem because any other code in the process using the same string, will share the same lock.

Reference: Remarks section in msdn.



来源:https://stackoverflow.com/questions/21473467/c-sharp-lock-string-not-working-for-dynamic-argument

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