ThreadLocal issue when closing application

This forum is meant for questions and discussions about the X# language and tools
Post Reply
leon-ts
Posts: 435
Joined: Fri Feb 03, 2017 1:43 pm

ThreadLocal issue when closing application

Post by leon-ts »

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
Best regards,
Leonid
User avatar
Chris
Posts: 4907
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

ThreadLocal issue when closing application

Post by Chris »

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?
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
User avatar
robert
Posts: 4520
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

ThreadLocal issue when closing application

Post by robert »

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
XSharp Development Team
The Netherlands
robert@xsharp.eu
leon-ts
Posts: 435
Joined: Fri Feb 03, 2017 1:43 pm

ThreadLocal issue when closing application

Post by leon-ts »

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:

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
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:
Exception Unhandled: System.ObjectDisposedException: Cannot access a disposed object. Object name: ThreadLocal.
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.

Best regards,
Leonid
Best regards,
Leonid
User avatar
Chris
Posts: 4907
Joined: Thu Oct 08, 2015 7:48 am
Location: Greece

ThreadLocal issue when closing application

Post by Chris »

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

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);
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?
Chris Pyrgas

XSharp Development Team
chris(at)xsharp.eu
leon-ts
Posts: 435
Joined: Fri Feb 03, 2017 1:43 pm

ThreadLocal issue when closing application

Post by leon-ts »

Hi Chris,
Thank you for the clarification!

Best regards,
Leonid
Best regards,
Leonid
Post Reply