mono / mono-addins

Mono.Addins is a generic framework for creating extensible applications, and for creating add-ins which extend those applications.
MIT License
163 stars 94 forks source link

Make mono.addins thread safe #187

Closed slluis closed 2 years ago

slluis commented 2 years ago

Makes Mono.Addins safe to use from multiple threads. Most internal collections have been converted to immutable, so normal access to the extension tree is lock-free, so it should be fast. Locks are acquired when the tree is built (on demand).

Some noticeable changes:


Mono.Addins is now thread safe, meaning that it is possible and safe to use AddinManager, AddinEngine and related classes to access the extension model from different threads.

Mono.Addins by itself does not use multiple threads. If the add-in engine is always used from a single thread, then the behavior is the same as it used to be before thread-safety support. There are however several considerations to take in to account when using Mono.Addins in a multi-threaded application.

Extension model queries

The extension model is a mutable data structure. Extension nodes can be added or removed as a result of conditions changing or add-ins being enabled or disabled. Methods like ExtensionContext.GetExtensionNodes() return a snapshot of the nodes at the time of the call, and that snapshot won't change. However, consecutive calls to that method may return different results if the extension model mutates between calls.

Event Handlers

The AddinManager, AddinEngine, ExtensionContext and ExtensionNode classes have events that are raised when the extension model changes. In a multi-threaded application, those events may be raised in different threads, depending on which thread the change was originated. Subscribers of those events must take that into account and take thread safety measures by themselves if necessary.

In any case, Mono.Addins guarantees that events for a specific extension context are raised sequentially. For example, if a child node is added and removed from a node, the corresponding Add event handler will be executed first, and when it completes the Remove handler will be executed next.

Custom extension nodes

It is up to Mono.Addins extenders to guaratee the thread safety of custom extension nodes. The implementation must take into account that nodes can be created in different threads, and that virtual methods such as OnChildNodeAdded or OnChildNodeRemoved can also be invoked from different threads (those methods however are executed sequentially, like explained above for events).

Conditions

Custom conditions may need to be evaluated from different threads, so the ConditionType.Evaluate() method should be thread safe. The ConditionType.NotifyChanged() method, used to notify that the condition has changed, can be invoked from any thread. Extension model change events caused by condition changes will be raised in the thread that invoked NotifyChanged().

Therzok commented 2 years ago

I still haven't had a chance to review this, sorry!

Therzok commented 2 years ago

Mostly LGTM!