Alaska Software Inc. - Re: DataObject xbase 2.0 726
Username: Password:
AuthorTopic: Re: DataObject xbase 2.0 726
Andreas Gehrs-Pahl

View the complete thread for this message in:

Re: DataObject xbase 2.0 726
on Tue, 18 Oct 2016 09:36:23 -0400
Raffaele,

I wrote:

>That should basically work and the application shouldn't hang anymore.

It actually doesn't work! I have even tried to get this to work by using 
an Abstract Class with Synch(ed) SetNoIVar() / GetNoIVar() methods and an 
internal, protected DataObject, but it still hangs when adding a new iVar 
to the internal DataObject, even when it is done inside a Synch Method, 
resulting in all the threads waiting for each other. This hang-up seems to 
happen whenever you try to add a new Instance Variable to a DataObject which 
already has several Instance Variables, and which has been "used" in (or 
accessed from) multiple threads, no matter in which thread you try to add 
the new Instance Variable. 

I would characterize this as a bug and you might want to contact Alaska and 
have them create a PDR for this issue.

As a workaround, I have written my own substitute DataObject class, called 
AGP_DataObject(), which will fix those issues by simply using two internal 
Arrays for Instance Variables and Methods. The attached source code 
implements this class and some tests.

This implementation uses Sync Methods, so it is completely thread-safe, 
even when executing a dynamic Method. The entire method will be executed 
before a different thread has access to the data of the object, making sure 
that the data integrity isn't compromised. This might be an issue if a 
method takes a long time to complete, but data integrity is more important 
to me than raw speed.

And the most surprising thing is that using AGP_DataObjects is virtually 
as fast as using standard DataObjects, at least when the number of iVars 
is relatively small.

The AGP_DataObject class also includes a method named :DataObject() that 
creates/exports a genuine DataObject with the exact same structure as the 
one the AGP_DataObject is emulating.

The :Merge() method can be used to initialize/create (or update) a new or 
existing AGP_DataObject from another object -- either from a DataObject or 
from another AGP_DataObject. 

Also, the :Copy() method works differently than the :Copy() method of the 
standard DataObject class, and creates a non-dependent non-shallow copy of 
the object. Additionally, the :ClassDescribe() method has an option to 
create a result similar to the DataObject class.

I also included methods to remove dynamic/virtual Instance Variables as well 
as dynamic/virtual Methods, and to sort them, mainly for aesthetic reasons.

The one thing that I couldn't implement is access to Instance Variables via 
the (Array) Index Operator, as in: oDataObject[n], which returns the value 
of the n-th Instance Variable of the oDataObject. Even though I think this 
is a completely useless (and dangerous) coding style -- as you normally 
don't know (for sure) in which order Instance Variables will be (or have 
been) created -- some Xbase++ routines rely on this feature. This includes 
the Var2XML() function, which uses this feature because it is apparently 
faster than accessing the iVars by name. I'm also not sure how this index 
feature affects purely virtual iVars, which are implemented by using only 
Access/Assign Methods.

Anyway, if you want to use this "access via index" feature, you can always 
create a genuine DataObject from the AGP_DataObject with the :DataObject() 
method.

Until Alaska implements a thread-safe DataObject class, my AGP_DataObject 
class is probably the best alternative to use in a multi-thread environment, 
though. I'm using it myself; without any problems (so far.)

Please let us know if this Class fixes your issues!

Thanks,

Andreas

Andreas Gehrs-Pahl
Absolute Software, LLC

phone: (989) 723-9927
email: Andreas@AbsoluteSoftwareLLC.com
web:   http://www.AbsoluteSoftwareLLC.com
[F]:   https://www.facebook.com/AbsoluteSoftwareLLC

AGP_DataObjects.zip