Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: under ARC, does someone can explain me this behavior and how to fix it?


This question is not answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 4 - Last Post: Mar 30, 2016 4:22 PM Last Post By: loki loki
loki loki

Posts: 787
Registered: 7/1/02
under ARC, does someone can explain me this behavior and how to fix it?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 29, 2016 3:46 PM
hello,

under ARC (nextgen), i have a frame, and in this frame i have a procedure below :

procedure TMyFrame.MyProcedure
var aTask: iTask;
begin
MainAniIndicator.Visible := True;
MainAniIndicator.Enabled := True;

aTask := TTask.Create (procedure ()
begin

TThread.Synchronize(nil,
procedure
begin
MainAniIndicator.Enabled := false;
MainAniIndicator.Visible := false;
end);

end);

aTask.Start;
sleep(5000); // <=now we are sure the the task is completed
end;

now the problem, if i do
MyFrame.free
then everything is ok, myframe is destroyed from the memory

BUT if i do
MyFrame.myProcedure;
MyFrame.free;

then Myframe will be never destroyed :( and i have now idea what to do :(
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: under ARC, does someone can explain me this behavior and how to fix it?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 29, 2016 5:53 PM   in response to: loki loki in response to: loki loki
loki wrote:

under ARC (nextgen), i have a frame, and in this frame i have
a procedure below :

You do realize this code is completely useless, don't you? You are starting
a TTask that runs in its own worker thread, whose sole purpose is to sync
with the main UI thread to stop and hide the AniIndicator. Creating a thread
that simply syncs with the main UI is a useless waste of a worker thread.
But also, while your main UI thread is sleeping for 5 seconds, it cannot
process UI updates or the Synchronize() request at all. In your example,
the Synchronize() request will not be processed until after Sleep() is done
and MyProcedure() exits and control is returned to the main UI message loop.

There is no point in using TTask in this manner at all. At the very least,
a better example would have been to put the Sleep() inside the TTask instead,
to simulate some activity being performed in the background, while the main
UI thread is free to continue processing UI updates and other messages until
the task is finished at some later time.

procedure TMyFrame.MyProcedure
var
  aTask: iTask;
begin
  MainAniIndicator.Visible := True;
  MainAniIndicator.Enabled := True;
  aTask := TTask.Create (
    procedure ()
    begin
      Sleep(5000); // do something that takes some time to complete...
      TThread.Synchronize(nil,
        procedure
        begin
          MainAniIndicator.Enabled := false;
          MainAniIndicator.Visible := false;
        end
      );
    end
  );
  aTask.Start;
end;


Even then, I probably wouldn't use Synchronize(), I would use Queue() instead:

procedure TMyFrame.MyProcedure
var
  aTask: iTask;
begin
  MainAniIndicator.Visible := True;
  MainAniIndicator.Enabled := True;
  aTask := TTask.Create (
    procedure ()
    begin
      Sleep(5000); // do something that takes some time to complete...
      TThread.Queue(nil,
        procedure
        begin
          MainAniIndicator.Enabled := false;
          MainAniIndicator.Visible := false;
        end
      );
    end
  );
  aTask.Start;
end;


now the problem, if i do

MyFrame.free

then everything is ok, myframe is destroyed from the memory

Do it where exactly? I am assuming you mean everything is fine if you call
Free() without calling MyProcedure() first, correct?

BUT if i do

MyFrame.myProcedure;
MyFrame.free;

then Myframe will be never destroyed :(

It will be freed eventually, but not when Free() is called. Remember that
under ARC, objects are reference counted. Free() simply decrements the reference
count. The object is not actually freed until its reference count falls
to 0. Your anonymous procedures have captured a reference to the MainAniIndicator
object, thus incrementing its reference count. And MainAniIndicator itself
has references to your Frame object, so its reference count is incremented
as well. Until the TTask has finished running completely, those references
will stay alive.

--
Remy Lebeau (TeamB)
loki loki

Posts: 787
Registered: 7/1/02
Re: under ARC, does someone can explain me this behavior and how to fix it?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 30, 2016 2:37 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
You do realize this code is completely useless, don't you?

off course this code is "fully" useless :) :) it's was just to show the problem :)

There is no point in using TTask in this manner at all. At the very least,
a better example would have been to put the Sleep() inside the TTask instead,
to simulate some activity being performed in the background, while the main
UI thread is free to continue processing UI updates and other messages until
the task is finished at some later time.

yes, i made bad exemple with sleep, but was just to show the problem :)

now the problem, if i do

MyFrame.free

then everything is ok, myframe is destroyed from the memory

Do it where exactly? I am assuming you mean everything is fine if you call
Free() without calling MyProcedure() first, correct?

correct :) :)


BUT if i do

MyFrame.myProcedure;
MyFrame.free;

then Myframe will be never destroyed :(

It will be freed eventually, but not when Free() is called. Remember that
under ARC, objects are reference counted. Free() simply decrements the reference
count. The object is not actually freed until its reference count falls
to 0. Your anonymous procedures have captured a reference to the MainAniIndicator
object, thus incrementing its reference count. And MainAniIndicator itself
has references to your Frame object, so its reference count is incremented
as well. Until the TTask has finished running completely, those references
will stay alive.

no no, even when the ttask is finished, myframe will be not free :(
that the problem!! the refcount to the myframe never go down to 0 :(
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: under ARC, does someone can explain me this behavior and how to fixit?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 30, 2016 10:00 AM   in response to: loki loki in response to: loki loki
loki wrote:

no no, even when the ttask is finished, myframe will be not free :(
that the problem!! the refcount to the myframe never go down to 0 :(

I wouldn't expect Free() to work in this case, even without calling MyProcedure(),
because any components placed on the Frame will have references to the Frame,
so its reference count should never be able to fall to 0. Check the Frame's
RefCount property before creating the TTask and after calling Free(). If
you want to force destruction, use DisposeOf() instead of Free().

--
Remy Lebeau (TeamB)
loki loki

Posts: 787
Registered: 7/1/02
Re: under ARC, does someone can explain me this behavior and how to fixit?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 30, 2016 4:22 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
I wouldn't expect Free() to work in this case, even without calling MyProcedure(),
because any components placed on the Frame will have references to the Frame,
so its reference count should never be able to fall to 0. Check the Frame's
RefCount property before creating the TTask and after calling Free(). If
you want to force destruction, use DisposeOf() instead of Free().

disposeOF it's a little ugly thing made by delphi to support arc. i think it's always bad to use it.
disposeof not really free the object, but make it like a "zombie", call his destroy but keep the object in memory still his refcount <> 0
in good arc system disposeof must even not exist

actually what i do is simple

var aSelfP: Pointer;
aSelfP := pointer(self);

and use TmyFrame(aSelfP) instead in the anonymous method :)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02