0

As I understand it, I need to use ReaderWriterLockSlim from here: https://learn.microsoft.com/en-us/dotnet/api/system.threading.readerwriterlockslim

I did everything like theirs, crashes with System.NullReferenceException:

Object reference not set to an instance of an object.

Updated .... OK, I removed the check for null and added a check for the version of the object in each reading trade. Now works without errors - thanks Peter Duniho

 using System;
    using System.Threading;

    public class Player {
        public int id;
        public override string ToString() {
            return id.ToString();
        }
    }
    public class SlimTest{
        ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
        Random R = new Random();
        Player _leader;
        public Player leader {
            get {
                locker.EnterReadLock();
                try {
                    return _leader;
                }
                finally {
                    locker.ExitReadLock();
                }
            }
        }
        int _id = 0;
        public SlimTest() {
            var main = new Thread(() => {
                while(true) {
                    locker.EnterWriteLock();
                    try {
                        var cf = R.Next(1, 10) % 2;
                        if(cf > 0)
                            _leader = new Player() { id = _id += 1 };
                    }
                    finally {
                        locker.ExitWriteLock();
                    }
                    Thread.Sleep(R.Next(3, 10));
                }
            });
            main.IsBackground = true;
            main.Start();


            for(int i = 0; i < 10;i++) {
                var reader = new Thread(() => {
                    int my_id=0;
                    while(true) {
                        if(leader == null)
                            continue;
                        if(my_id != leader.id) {
                            my_id = leader.id;
                            Console.Write(leader.id);
                        }
                        else
                            Console.Write(".");
                        Thread.Sleep(R.Next(3, 10));
                    }
                 
                });
                reader.IsBackground = true;
                reader.Start();
            }
        }
    }
  • Hint: a thread can be pre-empted **at any time**. Even between the time you read a property once to check whether it's `null`, and the time you read it again to actually use the value. See duplicate for extensive advice on debugging `NullReferenceException`. You may find it useful to think about whether you want to use the `ReaderWriterLock` to ensure the value can't change while you're still looking at it, or you just want to make a copy of the value in a local variable, and then use just that local variable, which you know can't change from another thread. – Peter Duniho Jun 04 '21 at 02:41
  • I have a very simple scenario. There is a main thread in which calculations take place, and there is an object that reflects them. Several other threads read this object and perform certain actions depending on the state of the object. Of course, I can add an error handler, but then I don't need ReaderWriterLockSlim at all, which in fact doesn't work. – Stanislav Wlaskin Jun 04 '21 at 03:29
  • The `ReaderWriterLockSlim` class works perfectly. If you use it correctly. You have all the information here that you need to fix the problem, including my comment above which details precisely what the problem is, and of course the linked question that gives you lots of advice about debugging the exception. – Peter Duniho Jun 04 '21 at 03:31
  • I understand correctly that in my case you propose that each thread should copy a copy of the main object to itself and work only with it? This option doesn't suit me at all. At a certain state of the main object (conditionally it is equal to zero), all child threads must stop their work – Stanislav Wlaskin Jun 04 '21 at 03:36
  • _"each thread should copy a copy of the main object to itself "_ -- no, that's not my suggestion at all. You only need to take a copy of the _reference_, not the object itself. Note, of course, that that applies to the code you posted above. If you have other requirements in some other code you haven't shared, then information that is useful for this question may or may not be useful in that other context. – Peter Duniho Jun 04 '21 at 03:39
  • Read the instance variable once; `var currentLeader = this.leader;` I'd also recommend making `Player` immutable, either using the new `record` support, or just readonly fields `public readonly int id;`. Then you don't really need locking. When you read `this.leader` you'll get a valid value. – Jeremy Lakeman Jun 04 '21 at 04:33
  • Yes, with `var currentLeader = this.leader;` it works fine, even without any ReaderWriterLockSlim In Main thred. Thanks – Stanislav Wlaskin Jun 04 '21 at 22:53

0 Answers0