0

In this answer given on implementing a thread-safe tree by jim-mischel, he states:

The easiest way to do this would be to protect the entire tree with a ReaderWriterLockSlim. That allows concurrent access by multiple readers or exclusive access by a single writer. Any method that will modify the structure in any way will have to acquire the write lock, and no other threads will be allowed to read or write to the structure until that thread releases the write lock.

If I'm following correctly, this would mean that the methods/properties for the tree structure would look something like:

    public class TreeNode
    {

        private String BackingData = "";
        public String Data 
        {
            get
            {
                lock (LockObject)
                    return BackingData;
            }
            set
            {
                lock (LockObject)
                    BackingData = value;
            }
        }

        private TreeNode BackingParent { get; set; }
        public TreeNode Parent
        {
            get
            {
                lock (LockObject)
                    return BackingParent;
            }
        }

        //etc...

        private List<TreeNode> BackingChildren { get; }
        private Object LockObject { get; }

        TreeNode()
        {
            BackingData = "";
            BackingParent = null;
            BackingChildren = new List<TreeNode>();
            LockObject = new Object();
        }

    }

The thing is, this is not protecting the entire tree - it's protecting not even individual nodes of a tree, and even then only the individual methods/properties.

How could this be arranged such that the entire tree is protected?

I did think about holding a static class that maps the root TreeNodes to an Object. Then, having a couple of methods in this static class that lock and unlock according to the root TreeNode using the Monitor methods. The Monitor.IsEntered method could be used within the TreeNodes, but to check that this is locked, we'd still need to walk up the unlocked tree to get the root TreeNode. Even then, I wouldn't know how to handle if IsEntered was false.

Is there any suitable way to lock an object, and thus all child objects that may be held by said object?

Harry Will
  • 131
  • 7
  • Why is `lock(somePrivateObj) { // do something with shared tree reference }` not good enough? If you can only reach children via the shared tree reference, then you only need to lock before doing anything with that – JohanP Jun 01 '21 at 06:56
  • Well, in the code I provided, there is nothing stopping one part of the tree from being manipulated alongside another part of the tree via different threads. Due to the structure I have, that's not something I can allow. I'm wanting to find a way for the entire structure to be locked. – Harry Will Jun 01 '21 at 07:06
  • How would the other part of the tree be manipulated if you have a lock on the root node? I'm assuming your code would be something like `TreeNode _root = new TreeNode(); // build tree` then later on, you will have some method that needs to modify some part, at that point, you can `lock(obj) { _root.Parent.Data = "Modified"}`. You can only access the other nodes through `_root`, the `Parent` and `BackingChildren` aren't global variables – JohanP Jun 01 '21 at 07:14
  • Just so we're on the same page... Every TreeNode has other TreeNode objects as children, and has one reference to a parent TreeNode. And each TreeNode has various properties which may be manipulated and wrapped in a LockObject that is local to said TreeNode. As all TreeNodes are classes - I could easily end up with references to TreeNodes that are not the root Node. There is nothing stopping from the properties being called, thus ignoring the lock held by the root TreeNode. – Harry Will Jun 01 '21 at 07:24
  • How does your global/shared variable look for your tree? Is it a single TreeNode or do you have a List nodes? – JohanP Jun 01 '21 at 07:28
  • There is one single TreeNode that is the root node – Harry Will Jun 01 '21 at 07:29
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/233159/discussion-between-harry-will-and-johanp). – Harry Will Jun 01 '21 at 07:30
  • lock tree: https://github.com/AtakamaLLC/hilok – Erik Aronesty Jan 10 '23 at 20:13

1 Answers1

1

The easiest way to protect your shared tree node reference is to lock on a globally shared private variable. This will get you to where you need to be with respect to thread safety. It is not the most efficient solution as the entire tree is locked but I doubt that it will cause any concern.

So whenever any of your functions touch the global root node, make sure that you

lock(mutex)
{
    _root.Parent.Data = "Modified";
}

and this will ensure that a single thread is allowed in at a time.

JohanP
  • 5,252
  • 2
  • 24
  • 34