In my plug-in, I get the following exception on Rhino shutdown. Has anybody seen something similar or can give me a pointer as to what kind of operations could lead to this behavior? I’m not yet really able to track down the culprit, but will update the post if I can narrow it down to a few calls that are involved in causing it.
System.Transactions Critical: 0 : <TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Critical"><TraceIdentifier>http://msdn.microsoft.com/TraceCodes/System/ActivityTracing/2004/07/Reliability/Exception/Unhandled</TraceIdentifier><Description>Unhandled exception</Description><AppDomain>DefaultDomain</AppDomain><Exception><ExceptionType>System.ObjectDisposedException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType><Message>Cannot access a disposed object.
Object name: 'The ThreadLocal object has been disposed.'.</Message><StackTrace> at System.Threading.ThreadLocal`1.GetValueSlow()
at System.Collections.Concurrent.ConcurrentBag`1.GetThreadList(Boolean forceCreate)
at Rhino.DocObjects.ObjRef.Finalize()</StackTrace><ExceptionString>System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'The ThreadLocal object has been disposed.'.
at System.Threading.ThreadLocal`1.GetValueSlow()
at System.Collections.Concurrent.ConcurrentBag`1.GetThreadList(Boolean forceCreate)
at Rhino.DocObjects.ObjRef.Finalize()</ExceptionString></Exception></TraceRecord>
It’s not my ConcurrentBag that is being cleared out here. I assume, it is the ConcurrentBag that is being cleared in Rhino’s HostUtils.DeleteObjectsOnMainThread.
Sorry, I didn’t word properly. I meant to ask: did you make sure you clear out your concurrent bag in the OnShutdown? You might want to do that explicitly.
I use a couple of ConcurrentDictionary and a couple of ConcurrentQueue in RhinoCycles. I make sure I clear them out manually during the plug-in OnShutdown.
Maybe I do misunderstand the issue here, but my assumption is the following:
There is some ObjRef whose finalizer is being called. In this finalizer, Rhino adds the object to a ConcurrentBag (HostUtils.AddObjectsToDeleteOnMainThread) to be cleared out. Then, when clearing out the ConcurrentBag in HostUtils.DeleteObjectsOnMainThread, Rhino iterates through those objects in the following way:
IDisposable result;
while (g_objectsToDisposeOnMainThread.TryTake(out result))
{
result?.Dispose();
}
In the StackOverflow page linked above, there is an explanation how this can lead to an ObjectDisposedException.
This is something added by @stevebaer . To be able to debug this properly are you able to recreate the crash with a minimal example plug-in of which you can share the code here?
I haven’t been able to extract a minimal example, but eventually I found a way to fix the issue by disposing manually of the object references gathered during the command that causes it.
This is how it looks like more or less:
protected override Result RunCommand(RhinoDoc doc, RunMode mode)
{
var getObject = new GetObject
{
GeometryFilter = ObjectType.Mesh,
GroupSelect = true,
SubObjectSelect = false,
DeselectAllBeforePostSelect = false
};
getObject.AcceptNothing(true);
getObject.EnableClearObjectsOnEntry(false);
getObject.EnableUnselectObjectsOnExit(false);
while (true)
{
var getResult = getObject.GetMultiple(1, 0);
if (getObject.CommandResult() != Result.Success)
{
return getObject.CommandResult();
}
if (getObject.ObjectsWerePreselected)
{
getObject.EnablePreSelect(false, false);
continue;
}
if (getResult == GetResult.Object)
{
break;
}
}
var objectReferences = getObject.Objects();
var meshObjects = objectReferences.Select(o => o.Object()).OfType<MeshObject>().ToList();
// Something inside this method or its sub methods causes the issue
DoAShitTonOfStuff(meshObjects);
// Those lines fix it
foreach (var objectReference in objRefs)
{
objectReference.Dispose();
}
return Result.Success;
}