Hi,
There is a class A, in the destructor of which some function is called, which in turn uses the AScan function. The application (MDI) creates an object (instance) of class A in one of its windows and does not explicitly destroy it (this is not necessary). This object will be destroyed when GC is called. When the application (MDI) is closed, the destructor is called on the instance of class A. Then it comes down to the AScan function, and it throws an ObjectDisposedException with a ThreadLocal object specified. As I understand it, ThreadLocal is used in RuntimeState.
Why is the ThreadLocal disposed before there are any objects that have not yet been destroyed that can use it?
P.S. The problem occurs in a real application. I tried to create a situation in a small test application, but the problem did not appear there.
Best regards,
Leonid
ThreadLocal issue when closing application
ThreadLocal issue when closing application
Best regards,
Leonid
Leonid
ThreadLocal issue when closing application
Hi Leonid,
hard to tell, without seeing the code. What is the exact excception message that you get? Also can you please show the code of the destructor?
hard to tell, without seeing the code. What is the exact excception message that you get? Also can you please show the code of the destructor?
Chris Pyrgas
XSharp Development Team
chris(at)xsharp.eu
XSharp Development Team
chris(at)xsharp.eu
ThreadLocal issue when closing application
Leonid
If you want TO clean up before the local storage is gone then I recommend that you create an exit procedure:
Procedure SomeName EXIT
// clean up here
The compiler creates a special function that calls all exit procedures at app shutdown when the runtime is still intact.
Robert
If you want TO clean up before the local storage is gone then I recommend that you create an exit procedure:
Procedure SomeName EXIT
// clean up here
The compiler creates a special function that calls all exit procedures at app shutdown when the runtime is still intact.
Robert
XSharp Development Team
The Netherlands
robert@xsharp.eu
The Netherlands
robert@xsharp.eu
ThreadLocal issue when closing application
Hi,
The problem comes from the fact that in my application one of the classes had a bad finalizer design. I will not give a real example of the code because of its volume. This code was written in VO to support event handling. It was later transferred to X#. But for this discussion, I wrote an example that matches it:
The problem is that the implicit finalization of the MyClass is never called. This is due to the fact that the global __aListeners array stores a reference to an instance of the MyListenerClass class, which in turn stores a reference to MyClass in the oOwner field. As a result, the instance of the class MyClass is designated in the GC as "alive" and the destructor of the class MyClass is not called. And only when the application closes and the finalizers of all objects are called, then the destructor code presented above is executed. But at this point (in a real application, not in this example), the ThreadLocal object has already been destroyed and an exception is thrown on the AScan function:
Best regards,
Leonid
The problem comes from the fact that in my application one of the classes had a bad finalizer design. I will not give a real example of the code because of its volume. This code was written in VO to support event handling. It was later transferred to X#. But for this discussion, I wrote an example that matches it:
Code: Select all
STATIC GLOBAL __aListeners := {} AS ARRAY
FUNCTION AddListener(oListener AS MyListenerClass) AS VOID
LOCAL i AS DWORD
IF ( i := AScan( __aListeners, oListener ) ) == 0
__aListeners:Add(oListener)
ENDIF
RETURN
FUNCTION RemoveListener(oListener AS MyListenerClass) AS VOID
LOCAL i AS DWORD
IF ( i := AScan( __aListeners, oListener ) ) > 0
__aListeners:Delete(i)
__aListeners:Resize( __aListeners:Length - 1 )
ENDIF
RETURN
CLASS MyClass
HIDDEN oListener AS MyListenerClass
CONSTRUCTOR()
oListener := MyListenerClass{SELF}
AddListener(oListener)
RETURN
DESTRUCTOR()
RemoveListener(oListener)
RETURN
// MyClass methods and properties
// ...
END CLASS
CLASS MyListenerClass
HIDDEN oOwner AS OBJECT
CONSTRUCTOR( oOwner_ AS OBJECT )
SELF:oOwner := oOwner_
RETURN
// MyListenerClass methods and properties
// ...
END CLASS
Now I have added an implementation from IDisposable to the MyClass class and implemented the Dispose method, which deregisters the oListener object. And added code to the application that explicitly calls the Dispose method on an instance of the MyClass class. Now the problem does not arise. But the question still remains open, because the problem with the design of the code in my example only revealed the problem with ThreadLocal: when object finalizers are executed when the application is closed, it may be impossible to call functions such as AScan in them.Exception Unhandled: System.ObjectDisposedException: Cannot access a disposed object. Object name: ThreadLocal.
Best regards,
Leonid
Best regards,
Leonid
Leonid
ThreadLocal issue when closing application
Hi Leonid,
I think I see what's happening. AScan() internally calls SetExact() to use this setting when scanning for strings and SetExact() in turn accesses a ThreadLocal<RuntimeState> object, which apparently has been already disposed when the destructor of your object is called.
There's actually a safeguard mechanism when reading this object, with the code
so normally SetExact() should simply return FALSE on app shutdown, but I see that the _shutdown field never becomes TRUE in the runtime code. Robert, I guess you just forgot to assign this?
I think I see what's happening. AScan() internally calls SetExact() to use this setting when scanning for strings and SetExact() in turn accesses a ThreadLocal<RuntimeState> object, which apparently has been already disposed when the destructor of your object is called.
There's actually a safeguard mechanism when reading this object, with the code
Code: Select all
CLASS RuntimeState
PRIVATE STATIC _shutdown := FALSE AS LOGIC // To prevent creating state when shutting down PUBLIC
STATIC METHOD GetValue<T> (nSetting AS XSharp.Set) AS T
IF _shutdown
// There is no RuntimeState when shutting down
RETURN Default(T)
ENDIF
RETURN currentState:Value:_GetThreadValue<T>(nSetting);
Chris Pyrgas
XSharp Development Team
chris(at)xsharp.eu
XSharp Development Team
chris(at)xsharp.eu
ThreadLocal issue when closing application
Hi Chris,
Thank you for the clarification!
Best regards,
Leonid
Thank you for the clarification!
Best regards,
Leonid
Best regards,
Leonid
Leonid