locked
Can multiple threads safely run the same method simultaneously? RRS feed

  • Question

  • Suppose I have a list of customers (with a simplified version like this):

    private sealed class Customer{
    	public string firstName;
    	public string lastName;
    }

    and then I build three collections of customers. I then call a process-Customer routine three times in rapid succession.

    Thread t1 = new Thread(new ParameterizedThreadStart(processCustomers));
    t1.Start(CustomerCollection1);
    t1 = new Thread(new ParameterizedThreadStart(processCustomers));
    t1.Start(CustomerCollection2);
    t1 = new Thread(new ParameterizedThreadStart(processCustomers));
    t1.Start(CustomerCollection3);

    Is this thread safe? Or do I need to do some locking? Let's assume that there are no global variables, that 'processCustomers' only uses local variables.

    Monday, November 25, 2013 2:31 PM

Answers

  • That depends a lot on how "processCustomers" looks like. If it is a static fucntion, that uses no varraible defined outside of the function and it's they are not writingh to the same data it should be treadsafe.

    If the 3 list's don't hold references to the same instances, then processing them in Parralell should also be threadsave.

    Inmutable types like string and all built in value types are also inherently threadsafe. If person is holding little to no Fuctions you might want to consider making it a struct instead.


    Let's talk about MVVM: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/b1a8bf14-4acd-4d77-9df8-bdb95b02dbe2 Please mark post as helpfull and answers respectively.


    • Edited by Christopher84 Monday, November 25, 2013 2:57 PM
    • Marked as answer by jal2 Monday, November 25, 2013 4:58 PM
    Monday, November 25, 2013 2:55 PM
  • It depends upon what each method is doing.  When talking about thread safety the general concern is that there are multiple writes to the same memory at the same time.  Any data that is accessible from multiple threads is considered to be a shared resource.  Managing access to the shared resource is what makes something thread safe or not.

    There are various ways to make a method thread safe depending upon what you need to do.  A method that does not use a shared resoure is thread safe.  A method that only writes to local (non-static) or non-shared variables is also thread safe.  When you move beyond that then you have to use locking or some other synchronization object if you need to ensure thread safety.  Note that not all methods need to be thread safe. 

    Let's take a couple of examples:

    int Add ( int x, int y ) { return x + y };

    This method only reads parameter values so it is thread safe.

    double Calculate ( int x, int  y )
    {
       var inst = x * 2;
       return inst * 0.5;
    }

    This method reads from a shared resource but is still thread safe.

    void DetermineSomethingAsync ( Employee employee ) { ... }
    void DetermineSomethingElseAsync ( Employee employee ) { ... }

    These methods would be thread safe (even if they got the same object) provided they only read the data.

    void UpdatePay ( Employee employee )
    {
       employee.Pay *= 2;
    }

    This method is not thread safe because we are updating the value of a potentially shared resource.  However if we know UpdatePay will not be called from multiple threads then there is no reason why we would make it thread safe.

    For your case if you intend to call ProcessCustomers on multiple threads but it only writes to non-shared resources then it is thread safe already.  In your example you're passing a separate collection each time so I'm assuming that is all the method works with.  Thus it is thread safe.  However if you were to pass the same collection to the method in different threads you would have an issue.

    Finally note that thread safety does not address the issue of thread ordering.  For example the following method is technically thread safe:

    bool IsInitialized ( ) { return someObj != null; }

    However this method may behave differently if another thread is writing to someObj.  The method itself is technically thread safe as it doesn't do anything that will cause other threads any issues but it might return back false when someObj is not null because of thread ordering.  Therefore any code that uses it may not behave properly.  In general if you are going to work with shared resources across threads you should ensure the code is thread safe.

    Michael Taylor
    http://msmvps.com/blogs/p3net

    • Marked as answer by jal2 Monday, November 25, 2013 4:58 PM
    Monday, November 25, 2013 2:55 PM

All replies

  • That depends a lot on how "processCustomers" looks like. If it is a static fucntion, that uses no varraible defined outside of the function and it's they are not writingh to the same data it should be treadsafe.

    If the 3 list's don't hold references to the same instances, then processing them in Parralell should also be threadsave.

    Inmutable types like string and all built in value types are also inherently threadsafe. If person is holding little to no Fuctions you might want to consider making it a struct instead.


    Let's talk about MVVM: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/b1a8bf14-4acd-4d77-9df8-bdb95b02dbe2 Please mark post as helpfull and answers respectively.


    • Edited by Christopher84 Monday, November 25, 2013 2:57 PM
    • Marked as answer by jal2 Monday, November 25, 2013 4:58 PM
    Monday, November 25, 2013 2:55 PM
  • It depends upon what each method is doing.  When talking about thread safety the general concern is that there are multiple writes to the same memory at the same time.  Any data that is accessible from multiple threads is considered to be a shared resource.  Managing access to the shared resource is what makes something thread safe or not.

    There are various ways to make a method thread safe depending upon what you need to do.  A method that does not use a shared resoure is thread safe.  A method that only writes to local (non-static) or non-shared variables is also thread safe.  When you move beyond that then you have to use locking or some other synchronization object if you need to ensure thread safety.  Note that not all methods need to be thread safe. 

    Let's take a couple of examples:

    int Add ( int x, int y ) { return x + y };

    This method only reads parameter values so it is thread safe.

    double Calculate ( int x, int  y )
    {
       var inst = x * 2;
       return inst * 0.5;
    }

    This method reads from a shared resource but is still thread safe.

    void DetermineSomethingAsync ( Employee employee ) { ... }
    void DetermineSomethingElseAsync ( Employee employee ) { ... }

    These methods would be thread safe (even if they got the same object) provided they only read the data.

    void UpdatePay ( Employee employee )
    {
       employee.Pay *= 2;
    }

    This method is not thread safe because we are updating the value of a potentially shared resource.  However if we know UpdatePay will not be called from multiple threads then there is no reason why we would make it thread safe.

    For your case if you intend to call ProcessCustomers on multiple threads but it only writes to non-shared resources then it is thread safe already.  In your example you're passing a separate collection each time so I'm assuming that is all the method works with.  Thus it is thread safe.  However if you were to pass the same collection to the method in different threads you would have an issue.

    Finally note that thread safety does not address the issue of thread ordering.  For example the following method is technically thread safe:

    bool IsInitialized ( ) { return someObj != null; }

    However this method may behave differently if another thread is writing to someObj.  The method itself is technically thread safe as it doesn't do anything that will cause other threads any issues but it might return back false when someObj is not null because of thread ordering.  Therefore any code that uses it may not behave properly.  In general if you are going to work with shared resources across threads you should ensure the code is thread safe.

    Michael Taylor
    http://msmvps.com/blogs/p3net

    • Marked as answer by jal2 Monday, November 25, 2013 4:58 PM
    Monday, November 25, 2013 2:55 PM
  • If your ProcessCustomer method doesn't make any changes to shared resources (static variables, objects shared by multiple Customers etc) you should be fine.

    On a separate note, do you really need the three different collections? If your goal is to process a collection of customers as fast as possible, I would suggest you have a look at the Parallel.Foreach() method. It's easier to deal with than handling your own threads, and it usually provides a faster result aswell (as it optimizes the number of threads etc.)

    You could do something like this:

    Parallel.ForEach(customerCollection, customer => customer.Process());
    

    For more information on Parallel.ForEach, see: http://msdn.microsoft.com/en-us/library/dd460720(v=vs.110).aspx

    Monday, November 25, 2013 3:03 PM
  • Thanks I didn't know about the Parallel.ForEach although I don't think I can use it for two reasons.

    (1) I suspect this is .Net 4.0

    (2) My code was simplified, I've actually got 3 different types of collections (instead of three instances of the Customer collection).

    Thanks!

    Monday, November 25, 2013 4:52 PM