Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixup management of managed and unmanaged resources #101

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

kevinpeizner
Copy link

@kevinpeizner kevinpeizner commented Feb 18, 2021

WIP

🚧 👷 🏗️

... this is a work in progress but I want to create draft to provide an opportunity for discussion.

Background

This work stems primarily from reading the .NET documentation about implementing the "dispose pattern".

According to this section documentation, the implementation of a void Dispose(bool disposing) method should:

  • Free unmanaged resources (a.k.a. unmanaged memory, file handles, etc.)
  • A conditional block that frees managed resources. (i.e. other IDisposable objects) that executes only if invoked from void Dispose()

The documentation also states that "If the method call comes from a finalizer, only the code that frees unmanaged resources should execute."

PR Summary

This PR is an attempt to fix some of the classes that must follow the "dispose pattern". The classes affected by this PR:

  • AsyncBase<T>
  • NngAlloc
  • NngCtx
  • NngDialer
  • NngListener
  • NngSocket
  • NngStat
  • NngString

Other Thoughts

In the process of working on this it appears that there are cases for an IDisposable to be "owned" by more than one entity which makes clean up difficult - which "owner" should be responsible for invoking Dispose() on the object? 🤷

Example:

  1. a user creates a nng.RepSocket
  2. the user creates a AsyncBase<T> class by passing the nng.RepSocket to CreateRepReqAsyncContext()
  3. Now both the user and the ASyncBase<T> "own" the nng.RepSocket
    Since nng.RepSocket is an IDisposable object, someone must invoke its Dispose() method... but who?

This type of problem appears to be a known limitation with IDisposable. A brief searching of the web shows some have implemented reference counting wrappers around IDisposable objects as a solution (similar to C++ shared_ptr): https://stackoverflow.com/a/22092381

Addressing this probably wont be a small task and seems to fall outside the scope of this PR (at least for now).

The NngDialer.NativeNngStruct is an unmanaged resource and therefore
needs to always be cleaned up in the protected virtual void
Dispose(bool) method.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload

Also, since this class contains an unmanaged resource a finalizer must
also be provided.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern
The NngSocket.NativeNngStruct is an unmanaged resource and therefore
needs to always be cleaned up in the protected virtual void
Dispose(bool) method.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload

Also, since this class contains an unmanaged resource a finalizer must
also be provided.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern
The NngDialer.NativeNngStruct is an unmanaged resource and therefore
needs to always be cleaned up in the protected virtual void
Dispose(bool) method.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload

Also, since this class contains an unmanaged resource a finalizer must
also be provided.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern
The NngAlloc.Ptr is an unmanaged resource and therefore
needs to always be cleaned up in the protected virtual void
Dispose(bool) method.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload

Also, since this class contains an unmanaged resource a finalizer must
also be provided.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern
The NngCtx.NativeNngStruct is an unmanaged resource and therefore
needs to always be cleaned up in the protected virtual void
Dispose(bool) method.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload

Also, since this class contains an unmanaged resource a finalizer must
also be provided.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern
Moved Finalize Dispose pattern from StatRoot class into its base class
NngStat.

The NngStat.NativeNngStruct is an unmanaged resource and therefore
needs to always be cleaned up in the protected virtual void
Dispose(bool) method.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload

Also, since this class contains an unmanaged resource a finalizer must
also be provided.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern

This also ensures that NngStat.NativeNngStruct is appropriately cleaned
up in StatChild as well.
The NngString.Ptr is an unmanaged resource and therefore
needs to always be cleaned up in the protected virtual void
Dispose(bool) method.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#the-disposebool-method-overload

Also, since this class contains an unmanaged resource a finalizer must
also be provided.

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose#implement-the-dispose-pattern
@codecov
Copy link

codecov bot commented Feb 18, 2021

Codecov Report

Merging #101 (8f1583a) into master (72a4395) will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##           master     #101   +/-   ##
=======================================
  Coverage   68.10%   68.10%           
=======================================
  Files          13       13           
  Lines         464      464           
  Branches       46       46           
=======================================
  Hits          316      316           
  Misses        132      132           
  Partials       16       16           
Flag Coverage Δ
unittests 68.10% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.


Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 72a4395...8f1583a. Read the comment docs.

@jeikabu
Copy link
Owner

jeikabu commented Feb 18, 2021

YES!
These exact changes were on my todo list after better understanding the Dispose pattern myself. I never thought anyone would notice much less tackle them so I never created an issue. Fire when ready.
It would be especially appreciated if you'd look at classes that derive from AsyncBase because they have to be handle specially to call the parent's Dispose().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants