2

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?

3 Answers 3

6

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.

Sign up to request clarification or add additional context in comments.

7 Comments

Note:This answer can help OP in particular scenario. but this is terribly bad practice and should be avoided in production code!
+0: Precise answer, but can't really upvote as it is indeed bad idea will likely cause only problems for OP... Note that with default implementation of ToString() this code is as good as locking on single static object lockObject = new object(); because default implementation of ToString() does not depend on the values of the type...
@AlexeiLevenkov No, If strings are created from stringbuilder or something then you'll end up having different references so that is not as same as locking on a static field static. I agree with you if they are compile time strings
@SriramSakthivel - I suspect your comment is about something else - string.Intern(something.ToString()) will always return the same value if type of something does not have custom implementation of ToString() because default ToString() simply returns type name...
@MuthukumarPalaniappan Why not. You need to synchronize access of a resource globally and decided to use lock("MyLock") and what if third parties or .net framework libraries uses sameway lock("MyLock"){Thread.Sleep(5000)}? Why do you want to synchronize with this?
|
5

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; } }
    }
}

2 Comments

thanks to your answer...but in my case, the parameter obj might not be same for both threads (edited in question). only the parameter.B value will be same for both threads.
You can't lock on value types... You may try to map your values to lock objects like Dictionary<int, object> and lock on objects corresponding to each value (assuming you want to protect pieces for different values separately)...
1

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.

3 Comments

oh!...is there other easy way to achieve this?
you should use same object to lock. lock(myLocker) where my locker is instance of object which should be shared in both the calls to ThreadFun
thanks to your answer...but in my case, the parameter obj might not be same for both threads (edited in question). only the parameter.B value will be same for both threads.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.