How to make static method thread safe?

18,942

Question 1: For my second method CommonFunction2, do I use a new static lock i.e. LockObjCommonFunction2 in this example or can I reuse the same lock object LockObj defined at the begining of the function.

If you want to synchronize these two methods, then you need to use the same lock for them. Example, if thread1 is accessing your Method1, and thread2 is accessing your Method2 and you want them to not concurrently access both insides, use the same lock. But, if you just want to restrict concurrent access to just either Method1 or 2, use different locks.

Question 2: Is there anything which might lead to threading related issues or can I improve the code to be safe thread.

Always remember that shared resources (eg. static variables, files) are not thread-safe since they are easily accessed by all threads, thus you need to apply any kind of synchronization (via locks, signals, mutex, etc).

Quesiton 3: Can there be any issues in passing common class instead of struct.. in this example SendMailParameters( which i make use of wrapping up all parameters, instead of having multiple parameters to the SendMail function)?

As long as you apply proper synchronizations, it would be thread-safe. For structs, look at this as a reference.

Bottomline is that you need to apply correct synchronizations for anything that in a shared memory. Also you should always take note of the scope the thread you are spawning and the state of the variables each method is using. Do they change the state or just depend on the internal state of the variable? Does the thread always create an object, although it's static/shared? If yes, then it should be thread-safe. Otherwise, if it just reuses that certain shared resource, then you should apply proper synchronization. And most of all, even without a shared resource, deadlocks could still happen, so remember the basic rules in C# to avoid deadlocks. P.S. thanks to Euphoric for sharing Eric Lippert's article.

But be careful with your synchronizations. As much as possible, limit their scopes to only where the shared resource is being modified. Because it could result to inconvenient bottlenecks to your application where performance will be greatly affected.

    static readonly object _lock = new object();
    static SomeClass sc = new SomeClass();
    static void workerMethod()
    {
        //assuming this method is called by multiple threads

        longProcessingMethod();

        modifySharedResource(sc);
    }

    static void modifySharedResource(SomeClass sc)
    {
        //do something
        lock (_lock)
        {
            //where sc is modified
        }
    }

    static void longProcessingMethod()
    {
        //a long process
    }
Share:
18,942
user1961100
Author by

user1961100

Updated on June 18, 2022

Comments

  • user1961100
    user1961100 almost 2 years

    I have written a static class which is a repository of some functions which I am calling from different class.

    public static class CommonStructures
    {
        public struct SendMailParameters
        {
            public string To { get; set; }
            public string From { get; set; }
            public string Subject { get; set; }
            public string Body { get; set; }
            public string Attachment { get; set; }
        }
    }
    
    public static class CommonFunctions
    {
        private static readonly object LockObj = new object();
        public static bool SendMail(SendMailParameters sendMailParam)
        {
            lock (LockObj)
            {
                try
                {
                    //send mail
                    return true;
                }
                catch (Exception ex)
                {
                    //some exception handling
                    return false;
                }
            }
        }
    
        private static readonly object LockObjCommonFunction2 = new object();
        public static int CommonFunction2(int i)
        {
            lock (LockObjCommonFunction2)
            {
                int returnValue = 0;
                try
                {
                    //send operation
                    return returnValue;
                }
                catch (Exception ex)
                {
                    //some exception handling
                    return returnValue;
                }
            }
        }
    }
    

    Question 1: For my second method CommonFunction2, do I use a new static lock i.e. LockObjCommonFunction2 in this example or can I reuse the same lock object LockObj defined at the begining of the function.

    Question 2: Is there anything which might lead to threading related issues or can I improve the code to be safe thread.

    Quesiton 3: Can there be any issues in passing common class instead of struct.. in this example SendMailParameters( which i make use of wrapping up all parameters, instead of having multiple parameters to the SendMail function)?

    Regards, MH