"making a "modify-while-enumerating" collection thread-safe" Code Answer

1

here is your class modified for thread safety:

class safeactionset
{
    object _sync = new object();
    list<action> _actions = new list<action>(); //the main store
    list<action> _delta = new list<action>();   //temporary buffer for storing added values while the main store is being enumerated
    int _lock = 0; //the number of concurrent invoke enumerations

    public void add(action action)
    {
        lock(sync)
        {
            if (0 == _lock)
            { //_actions list is not being enumerated and can be modified
                _actions.add(action);
            }
            else
            { //_actions list is being enumerated and cannot be modified
                _delta.add(action); //storing the new values in the _delta buffer
            }
        }
    }

    public void invoke()
    {
        lock(sync)
        {
            if (0 < _delta.count)
            { //re-entering invoke after calling add:  invoke->add,invoke
                debug.assert(0 < _lock);
                var newactions = new list<action>(_actions); //creating a new list for merging delta
                newactions.addrange(_delta); //merging the delta
                _delta.clear();
                _actions = newactions; //replacing the original list (which is still being iterated)
            }
            ++_lock;
        }
        foreach (var action in _actions)
        {
            action();
        }
        lock(sync)
        {
            --_lock;
            if ((0 == _lock) && (0 < _delta.count))
            {
                _actions.addrange(_delta); //merging the delta
                _delta.clear();
            }
        }
    }
}

i made a few other tweaks, for the following reason:

  • reversed if expressions to have constant value first, so if i do a typo and put "=" instead of "==" or "!=" etc., the compiler will instantly tell me of the typo. (: a habit i got into because my brain and fingers are often out of sync :)
  • preallocated _delta, and called .clear() instead of setting it to null, because i find it is easier to read.
  • the various lock(_sync) {...} give you your thread safety on all instance variable access. :( with the exception of your access to _action in the enumeration itself. ):
By Ilona Hari on April 10 2022

Answers related to “making a "modify-while-enumerating" collection thread-safe”

Only authorized users can answer the Search term. Please sign in first, or register a free account.