Threading issue over reference ANY type field within a class

My question is regarding statement assignment from an instance class done by a private ANY field property that references to an external field from a threaded file. To access the external field from the threaded file, it is done through a procedure that will make it possible to complete the reference, this way the ANY field will be considered as the field from the threaded file.

As an example

  1. A class declared in jcParentClass.inc and defined in jcParentClass.clw

Declaration in jcParentClass.inc

jcParentClass          CLASS(),TYPE,Module('jcParentClass.Clw'),LINK('jcParentClass.Clw',_JCLinkMode_),DLL(_JCDllMode_)
! Properties
Component                    ANY,PRIVATE
! Procedures
Init                                  PROCEDURE(), VIRTUAL  !Set the com
SetComponentField       PROCEDURE(*? Component), VIRTUAL  
                             END
  1. Definition in jcParentClass.clw
jcParentClass.Init                          PROCEDURE()

  CODE
  !Some code
!----------------------------------------------------------------------------------------
jcParentClass.SetComponentField PROCEDURE(*? Component)

  CODE
    SELF.Component &= Component
!----------------------------------------------------------------------------------------
  1. Program in Application.clw

Declaration of the file structure

Contact FILE,DRIVER('TOPSPEED'),NAME('Data\Dictionnaire'),PRE(DMLDict),CREATE,BINDABLE,THREAD ! 
RecIDkey KEY(Con:RecID),NOCASE,OPT,PRIMARY ! 
NameKey KEY(Con:Name),DUP,NOCASE,OPT ! 
Record     RECORD,PRE()
RecID         STRING(21) ! 
Name         STRING(55) ! 
               END
            END 

Instance of the ParentClass

jcChildClass               CLASS(jcParentClass)
!Properties and procedures
                                 END

  CODE
    OpeningFiles()
    jcChildClass.Init()
    Main 
  1. Source code of procedure Main in Main.clw file
    calling START(wUpdateContact,25000)
  1. Source code of procedure of wBrowseContact and wUpdateContact in wBrowseContact.clw and wUpdateContact.clw file respectively.

    From the source a call to the file manager global embed area of the Contact file is made, there is a call to Hide:Access:Contact.Init.

Hide:Access:Contact.Init PROCEDURE(File File,ErrorClass EC)

CODE
   jcChildClass.SetComponent(Name)
   PARENT.Init(File,EC)

On the first call to the procedure the Browse is opening but when I call the Browse a second time, deadlock , nothing is appearing. I’ve tried with the debugger to see exactly where the issue is occurring, it is hard to point the bug.

What I know the issue is when we do a reference within a thread, it cannot be recalled the way I did. All the assignment on the first time works perfectly over the referenced field. When the reference is done externally or globally nothing can be assigned because each thread is handling his own set of data, it fulfills its purpose which is exactly that. I must have done something that is not allowed or forgot some kind of declaration or else. I’ved tried with a thread attribute on the jcChildClass, oops, when I left the update procedure the program abort. I’m wondering if I need to add the THREAD attribute on each property of the class. If I do what I need to do exactly.

From the help I did follow this rule on how to reference to an ANY type field.

ā€œWhen an ANY variable is the destination of a reference assignment statement (destination &= source), the RTL disposes its previous internal data and replaces it with a new object which holds a reference to the source variable. If the source of a reference assignment is NULL, the RTL disposes the previous internal data of the ANY variable from the left side, and then sets the ANY to a NULL reference.ā€

I understand that we need to execute AnyTypeField reference to NULL before deleting a record from a queue.
Queue.AnyFieldType &= NULL
DELETING(Queue)
It is not the case here.

I’ve watched the Clarion Live webinars regarding thread which they are excellent; the webinar #64 with Paul Blais and Dennis Evans, #313, with Bruce Johnson and Mike Hanson, #533 and #534 with Mike Hanson. It did help me to understand more about thread on how it works and what we can do. I’ve tried to find a replication of this of some sort. I’m trying to find why it does that.

The question what exactly we need to do with an ANY property that reference a field from a threaded file within any thread and making sure there is no leak?

Thank you,
Robert

Seems kinda dangerous. Not sure how well ANY can handle references to threaded data between threads. Maybe it works fine.

Have you considered a class object with Set/Get methods and its own copy of the data? Then you could post an event or something that calls your class method to update the original source in a thread safe way.

1 Like

I just find out the text that I was working on 4 months ago was not posted. Sorry about that Jeff, because you have made me think a lot and today, furthermore. Here’s what I have written then.

You make me reflect about this, I need to do more investigation about this, it is fundamental on the project that I’m working on, the field type has to be generic, ANY type will do a great job, more searches needs to be done. Why it would be dangerous to reference an ANY type since we are able to assign the THREAD attribute. Yeah may the inner conversion. If I understand what you are suggesting to create a class that handles the Set and Get with its own set of data then post through an event a call to my class that is updating the original source. Yeah, I did consider that. From your reflection I kind of did that. I had to create the class and every time I needed it I had some type of duplication in the code. I came up with this Idea, the class is more generic to what I want to do. I only need to set the reference fields and all the procedures within the class. When I did the Set and Get with its own set of copy data, I do use the Set and Get, it is over the reference fields, with the ANY property I do not need to think about the data type, this way, the class will be more generic to the task I want to perform.

Is it possible to START a procedure in a new THREAD that has only instruction no window structure as such to be executed without having the stack overflow happening? What I want to do is to create a unit test program without any window or framework.

Hi Joliciel,

I don’t know if it will be useful but Dave Harms wrote a series of 5 articles in ClarionMag with the overall title ā€˜The Problem with Embeds’.
Part of that series described a Class and methodology for creating Unit Tests in Clarion.
All the PDFs (and source code) are available online here…

https://clarionmag.jira.com/wiki/spaces/archive/pages/399459/Monthly+PDFs+and+source+ZIPs

The articles are in the 2009 - 09 to 2009 - 12 PDFs

1 Like

Thanks Graham for the links, I will read the articles.

It’s absolutely possible, and very common, to start threads that don’t have a window. NetTalk web servers do this for each incoming request. The ThreadworkerClass also does it. Like I say, it’s pretty common.

That said, I don’t know what the ā€œstack overflow thingā€ is. I’ve never seen any kind of stack overflow error when starting threads…

Cheers
Bruce

Thank you Bruce for your response, I will read the documentation and the source code. Is there any particular area that I should look for, I have the Nettalk App licence, I know the server version is included?

Hi Robert,

I’m not really suggesting that NetTalk does it ā€œspecialā€ - I’m just pointing out that calling START is a common task - and calling START to a procedure without a window works just fine.

that said, if you open any of the WebServer examples, go to the WebServer procedure, then look for the method StartNewThread, you should see the generated code there.

Cheers
Bruce

If you are getting a stack overflow crash, look for some type of recursive call to a procedure or method. That will definitely create a stack overflow.
If you haven’t already, compile your program in debug and run the application in the debugger. Don’t set any breakpoints, just hit Go and run the program and recreate the crash.
The Stack trace window in the debugging should point you to the problem procedure/method.

1 Like

Sorry Rick not to respond as fast as I should, I thought I did reply after you wrote your comments. The message was holding on in the edit window to reply.

Thank you Rick, your suggestion has helped me to point out the cause of the stack overflow. It was coming from a threaded class within a non-threaded one; I believe that are not properly set up. It needs some work on the way the initialization of the class and the handling of its component.

As for the way the class work, the structure not the purpose of the class is based on the non-threaded Clarion ErrorClass and threaded ErrorStatusClass named jcWhenTaskClass and jcWhenTaskStatusClass. The interesting part from what I understand the ErrorClass will keep the error according to the initialized category from a TRN file where all errors are and the ErrorStatusClass will keep the generated errors within a specified thread at runtime. Meaning there is part of the ErrorClass is multithreaded through the ErrorStatusClass, where we see the procedures with the instruction ā€œlStatus &= INSTANCE(SELF.Status,THREAD())ā€.

What I need to do is to restructure part of the class, in a way it will prevent the stack overflow. I have been thinking about this quite a lot lately without getting into the code on how I will handle that, not an easy task.

Cheers,
Robert