Alaska Software Inc. - :InitClass() is not a sync method, it's a sync function
Username: Password:
AuthorTopic: :InitClass() is not a sync method, it's a sync function
Michael Hoffmann:InitClass() is not a sync method, it's a sync function
on Fri, 20 Jan 2012 11:12:01 +0100
Hello Alaskans,

the following code has added some gray hair to my exquisit collection. It 
shows, that :InitClass() is not synchronized on class level but on program 
level. That means only one thread may execute :InitClass() code at one time 
in a program. Hence an :InitClass() that waits for an :Initclass() to be 
completed in another thread will lead to a deadlock.

STATIC b_ready := .F.

CLASS A
  EXPORTED:
     CLASS METHOD InitClass
ENDCLASS

CLASS METHOD A:InitClass
   ? "In A:InitCLass()"
   Thread():New():Start({||B()})
   DO WHILE .NOT. b_ready
      Sleep(100)
   ENDDO
RETURN self

CLASS B
   EXPORTED:
     CLASS METHOD InitClass
ENDCLASS

CLASS METHOD B:InitClass
   ? "In B:InitCLass()"
   b_ready := .T.
RETURN self

FUNCTION Main
   A()
   ? "Done!"
   Inkey(0)
RETURN NIL
Michael HoffmannRe: :InitClass() is not a sync method, it's a sync function
on Fri, 20 Jan 2012 15:31:24 +0100
... even more gray hair.

Calling a class function collides with any :InitClass() in any other thread. 
Bottom line: If you have an :InitClass() that takes a little longer, every 
other thread will cease to run when it tries to access any other class, e.g. 
to create an instance, until the lengthy :InitClass() is done.

Here's the code to illustrate the situation...

STATIC b_ready := .F.

CLASS A
  EXPORTED:
     CLASS METHOD InitClass
ENDCLASS

CLASS METHOD A:InitClass
   ? "In A:InitCLass()"
   Thread():New():Start({||B(),b_ready := .T.})
   DO WHILE .NOT. b_ready
      Sleep(100)
   ENDDO
RETURN self

CLASS B
   EXPORTED:
     CLASS METHOD InitClass
ENDCLASS

CLASS METHOD B:InitClass
   ? "In B:InitCLass()"
RETURN self

FUNCTION Main
   B()
   A()
   ? "Done!"
   Inkey(0)
RETURN NIL
Jorge LRe: :InitClass() is not a sync method, it's a sync function
on Fri, 20 Jan 2012 12:29:26 -0300
Hi Michael

You should not to use the clause SYNC in your method ?


"Michael Hoffmann" escribió en el mensaje de 
noticias:1d19c00b$38a20e2f$b069e@news.alaska-software.com...

... even more gray hair.

Calling a class function collides with any :InitClass() in any other thread.
Bottom line: If you have an :InitClass() that takes a little longer, every
other thread will cease to run when it tries to access any other class, e.g.
to create an instance, until the lengthy :InitClass() is done.

Here's the code to illustrate the situation...

STATIC b_ready := .F.

CLASS A
  EXPORTED:
     CLASS METHOD InitClass
ENDCLASS

CLASS METHOD A:InitClass
   ? "In A:InitCLass()"
   Thread():New():Start({||B(),b_ready := .T.})
   DO WHILE .NOT. b_ready
      Sleep(100)
   ENDDO
RETURN self

CLASS B
   EXPORTED:
     CLASS METHOD InitClass
ENDCLASS

CLASS METHOD B:InitClass
   ? "In B:InitCLass()"
RETURN self

FUNCTION Main
   B()
   A()
   ? "Done!"
   Inkey(0)
RETURN NIL
Jorge LRe: :InitClass() is not a sync method, it's a sync function
on Fri, 20 Jan 2012 12:55:57 -0300
HI again

What i want to say..., if it is not better to initialize the thread first 
and then to use sync method

regards

"Michael Hoffmann" escribió en el mensaje de 
noticias:1d19c00b$38a20e2f$b069e@news.alaska-software.com...

... even more gray hair.

Calling a class function collides with any :InitClass() in any other thread.
Bottom line: If you have an :InitClass() that takes a little longer, every
other thread will cease to run when it tries to access any other class, e.g.
to create an instance, until the lengthy :InitClass() is done.

Here's the code to illustrate the situation...

STATIC b_ready := .F.

CLASS A
  EXPORTED:
     CLASS METHOD InitClass
ENDCLASS

CLASS METHOD A:InitClass
   ? "In A:InitCLass()"
   Thread():New():Start({||B(),b_ready := .T.})
   DO WHILE .NOT. b_ready
      Sleep(100)
   ENDDO
RETURN self

CLASS B
   EXPORTED:
     CLASS METHOD InitClass
ENDCLASS

CLASS METHOD B:InitClass
   ? "In B:InitCLass()"
RETURN self

FUNCTION Main
   B()
   A()
   ? "Done!"
   Inkey(0)
RETURN NIL
Michael HoffmannRe: :InitClass() is not a sync method, it's a sync function
on Fri, 20 Jan 2012 17:41:27 +0100
Hello Jorge,

:InitClass() works very much like a sync class method in case the class 
function is called on multiple threads at the same time. One thread must 
"win" in this siutation, create the class object and run the :InitClass() 
method for the class object. The call to the class function on the other 
thread will then return the same (already initialized) class object. Hence 
:InitClass() is very much like a sync method. However, according to my 
second example, the class function appears to be the synced code, which is 
even worse, because even if the class has already been initialized, the call 
to the class function will lead to a standstill of the calling thread in 
case any other thread is executing :InitClass() code.

Run the program and try to understand the implications. Any :InitClass() 
code running? => No class objects can be created and every call to the class 
function (e.g. MyClass():New()) in any other thread freze your program for 
this time.

Best regards,
Michael
Jorge LRe: :InitClass() is not a sync method, it's a sync function
on Fri, 20 Jan 2012 19:56:29 -0300
Hi Michael, thanks for the explanation

It would not throw the class directly, but his reference

CLASS METHOD A:InitClass
   Local K1
   ? "In A:InitCLass()"
   K1 := B()                         take the reference
   Thread():New():Start({|| K1 }, b_ready := .T. )
   DO WHILE .NOT. b_ready
      Sleep(100)
   ENDDO
RETURN self




"Michael Hoffmann" escribió en el mensaje de 
noticias:2c020941$21ecffc6$bf384@news.alaska-software.com...

Hello Jorge,

:InitClass() works very much like a sync class method in case the class
function is called on multiple threads at the same time. One thread must
"win" in this siutation, create the class object and run the :InitClass()
method for the class object. The call to the class function on the other
thread will then return the same (already initialized) class object. Hence
:InitClass() is very much like a sync method. However, according to my
second example, the class function appears to be the synced code, which is
even worse, because even if the class has already been initialized, the call
to the class function will lead to a standstill of the calling thread in
case any other thread is executing :InitClass() code.

Run the program and try to understand the implications. Any :InitClass()
code running? => No class objects can be created and every call to the class
function (e.g. MyClass():New()) in any other thread freze your program for
this time.

Best regards,
Michael
Michael HoffmannRe: :InitClass() is not a sync method, it's a sync function
on Sat, 21 Jan 2012 12:00:12 +0100
Hello Jorge,

thanks for your help. I know how to fix this particular problem, the code I 
posted was oversimplified to illustrate the problem. In reality your problem 
won''t be as simple as that and you will be wondering why your program stops 
to run because some background thread is stuck doing an InitClass on a class 
completely unrelated to the rest of your program.
This is like parachute jumping next to an alligator farm: Trouble waiting to 
happen.

Consider this: As long as my A:InitClass() is running on one thread (and 
that might take some time, because it must wait for B to be ready), you 
won't be able to call the class function on any other class on any other 
thread in your program, which would mean that this will stop your program 
when it does this: a := MyClass():New() or maybe xbp := XbpStatic():New().

In other words: Why should anything I do with class A influence anything I 
do with class B when they are otherwise unrelated?

Best regards,
Michael



"Jorge L" <jlborlando@way.com.ar> wrote in message 
news:5a6bf3c2$35ffb48a$c8029@news.alaska-software.com...
> Hi Michael, thanks for the explanation
>
> It would not throw the class directly, but his reference
>
> CLASS METHOD A:InitClass
>   Local K1
>   ? "In A:InitCLass()"
>   K1 := B()                         take the reference
>   Thread():New():Start({|| K1 }, b_ready := .T. )
>   DO WHILE .NOT. b_ready
>      Sleep(100)
>   ENDDO
> RETURN self
>
>
>
>
> "Michael Hoffmann" escribi en el mensaje de 
> noticias:2c020941$21ecffc6$bf384@news.alaska-software.com...
>
> Hello Jorge,
>
> :InitClass() works very much like a sync class method in case the class
> function is called on multiple threads at the same time. One thread must
> "win" in this siutation, create the class object and run the :InitClass()
> method for the class object. The call to the class function on the other
> thread will then return the same (already initialized) class object. Hence
> :InitClass() is very much like a sync method. However, according to my
> second example, the class function appears to be the synced code, which is
> even worse, because even if the class has already been initialized, the 
> call
> to the class function will lead to a standstill of the calling thread in
> case any other thread is executing :InitClass() code.
>
> Run the program and try to understand the implications. Any :InitClass()
> code running? => No class objects can be created and every call to the 
> class
> function (e.g. MyClass():New()) in any other thread freze your program for
> this time.
>
> Best regards,
> Michael
>