Properly locking a List<T> in MultiThreaded Scenarios?

Viewed 49430

Okay, I just can't get my head around multi-threading scenarios properly. Sorry for asking a similar question again, I'm just seeing many different "facts" around the internet.

public static class MyClass {
    private static List<string> _myList = new List<string>;
    private static bool _record;

    public static void StartRecording()
    {
        _myList.Clear();
        _record = true;
    }

    public static IEnumerable<string> StopRecording()
    {
        _record = false;
        // Return a Read-Only copy of the list data
        var result = new List<string>(_myList).AsReadOnly();
        _myList.Clear();
        return result;
    }

    public static void DoSomething()
    {
        if(_record) _myList.Add("Test");
        // More, but unrelated actions
    }
}

The idea is that if Recording is activated, calls to DoSomething() get recorded in an internal List, and returned when StopRecording() is called.

My specification is this:

  • StartRecording is not considered Thread-Safe. The user should call this while no other Thread is calling DoSomething(). But if it somehow could be, that would be great.
  • StopRecording is also not officially thread-safe. Again, it would be great if it could be, but that is not a requirement.
  • DoSomething has to be thread-safe

The usual way seems to be:

    public static void DoSomething()
    {
        object _lock = new object();
        lock(_lock){
            if(_record) _myList.Add("Test");
        }
        // More, but unrelated actions
    }

Alternatively, declaring a static variable:

    private static object _lock;

    public static void DoSomething()
    {
        lock(_lock){
            if(_record) _myList.Add("Test");
        }
        // More, but unrelated actions
    }

However, this answer says that this does not prevent other code from accessing it.

So I wonder

  • How would I properly lock a list?
  • Should I create the lock object in my function or as a static class variable?
  • Can I wrap the functionality of Start and StopRecording in a lock-block as well?
  • StopRecording() does two things: Set a boolean variable to false (to prevent DoSomething() from adding more stuff) and then copying the list to return a copy of the data to the caller). I assume that _record = false; is atomic and will be in effect immediately? So normally I wouldn't have to worry about Multi-Threading here at all, unless some other Thread calls StartRecording() again?

At the end of the day, I am looking for a way to express "Okay, this list is mine now, all other threads have to wait until I am done with it".

5 Answers
Related