justinstenning / SharedMemory

C# shared memory classes for sharing data between processes (Array, Buffer and Circular Buffer)
https://www.nuget.org/packages/SharedMemory
Other
569 stars 119 forks source link

Null Reference Exception When Disposing of Master Buffer #51

Closed wizardmanannan closed 4 years ago

wizardmanannan commented 4 years ago

Hello, I am getting a null reference exception within SharedMemory.RpcBuffer.ReadThreadV1(), when I call dispose on a MasterBuffer.

I am using SharedMemory to retrieve a port from a server process so that a client can connect to a service.

I would show you the call to dispose, but that would require pasting in a big blob of my code for it to make sense. If you need anything else let me know. What I can confirm though it that the master buffer is disposed first.

 public class SharedMemoryPortGetter : IPortGetter
    {
        RpcBuffer _rpcBuffer;
        public async Task<int> GetPort(string id)
        {
            if(_rpcBuffer == null)
            {
                _rpcBuffer = new RpcBuffer(id);
            }

            return (await _rpcBuffer.RemoteRequestAsync()).Data.FromBinary<int>();
        }

        private bool disposedValue = false; // To detect redundant calls

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    _rpcBuffer?.Dispose();
                }

                disposedValue = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }
    }
public class SharedMemoryPortSender : IPortSender
    {
        RpcBuffer _rpcBuffer;

        public void Init(GetPort getPort, string id)
        {
            _rpcBuffer = new RpcBuffer(id, (msgId, payLoad) =>
            {
                return getPort().ToBinary();
            });
        }

        private bool disposedValue = false; 

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    _rpcBuffer?.Dispose();
                }

                disposedValue = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }
    }
justinstenning commented 4 years ago

@alayGit is it the actual call to the masterBuffer.Dispose() that is triggering the error, or is it something else after you have disposed of the buffer?

wizardmanannan commented 4 years ago

Hello, Thanks for your reply. I revisited this issue, so that I could reply to your question.

I am experienced enough to know that usually when you have a problem calling a library that it is misuse of the library causing it, not the library. I wanted to paste this on a general help forum rather than an issues forum, but I couldn't find one :(. I am hoping someone could tell me what I am doing wrong.

Anyway in answer to your question it is definitely happening on the call to dispose, but from my retesting recently I discovered it is happening on the call to dispose of the second instance.

See here:

              try
                {
                    RpcPort = await _rpcPortGetter.GetPort(_rpcPortGetterId);
                    RealTimePort = await _realTimePortGetter.GetPort(_realTimePortGetterId);
                }
                finally
                {
                    _realTimePortGetter.Dispose();
                    _rpcPortGetter.Dispose();
                }

Both the _rpcPortGetter and _realTimePortGetter are instances of 'SharedMemoryPortGetter' (the code is in the first post). Also note that it matter not which order the dispose calls are done, it always happens on the second invocation.

justinstenning commented 4 years ago

@alayGit can you please prep a minimal standalone reproduction of the error and I'll take a look for you.

wizardmanannan commented 4 years ago

Just to let you know I have seen this message and I am onto creating this example. I should have it soon.

wizardmanannan commented 4 years ago

Hello, I have been unable to produce a minimal example.

I am working on a huge project, so I stripped just about everything out to produce the example, but with most of the code stripped out the issue didn't happen.

The only addition clue I was able to glean was that, in the real project, if I ran the second dispose in the watch window or in a Task.Run the issue did not happen.

I suspect something might be disagreeing with Async/Await.

My suggestion is that unless that clue somehow resolves the mystery that you close this issue as not reproducible.

I have a work around; I will just dispose of it in a non async method.

Thank you for your time.

Should I close it or should you, sorry I am a github beginner.