[fpc-pascal] Re: Multi-threaded project with few locks (no Thread.waitfor). Memory consumption keeps increasing on Ubuntu 10.10 x64
Jonas Maebe
jonas.maebe at elis.ugent.be
Fri Oct 15 17:06:37 CEST 2010
On 15 Oct 2010, at 16:31, Andrew Brunner wrote:
> On Fri, Oct 15, 2010 at 9:24 AM, Jonas Maebe <jonas.maebe at elis.ugent.be
> > wrote:
>> You replaced a bunch of semaphore create/lock/unlock/destroy
>> operations with
>> calls to a function that does not do anything.
>
> I did not. I REMOVED create/destroy/lock/unlock. I ADDED calls to
> the ThreadManager's own functions for thread Resume and Suspend.
Yes, that's what I meant, because the ThreadManeger's SuspendThread
function does not do anything under Unix.
> Did
> you try executing the suspend command? What happened?
First of all, if you use tthread.create(true) (i.e., create a
suspended thread), then the "execute" method will never be called:
***
{$mode delphi}
uses
cthreads, classes, sysutils;
type
tmythread = class(tthread)
procedure execute;override;
end;
procedure tmythread.execute;
begin
writeln('executing');
end;
var
c: tmythread;
begin
writeln('creating thread suspended');
c:=tmythread.create(true);
sleep(500);
writeln('resuming thread');
c.resume;
c.waitfor;
c.free;
end.
***
Currently writes:
creating thread suspended
resuming thread
executing
With the patch, the last line is missing.
Secondly, ignoring this bug and suspending the thread inside itself:
***
{$mode delphi}
uses
cthreads, classes, sysutils;
type
tmythread = class(tthread)
procedure execute;override;
end;
procedure tmythread.execute;
begin
suspend;
writeln('executing');
end;
var
c: tmythread;
begin
writeln('creating thread suspended');
c:=tmythread.create(false);
sleep(500);
writeln('resuming thread');
c.resume;
c.waitfor;
c.free;
end.
***
Currently writes:
creating thread suspended
resuming thread
executing
With the patch:
creating thread suspended
executing
resuming thread
>> That barrier has nothing to do with "set values of variables before
>> calling
>> the inherited create method to their own creation" (although it's not
>> entirely clear to me you mean by that). If you set values that the
>> child
>> thread will read after that thread has already been created, this
>> memory
>> barrier will not help either. That barrier is again about memory
>> write
>> ordering, which could cause the newly started thread to not see all
>> writes
>> performed by the parent thread *before* creating the child thread.
>
> Other than waiting for the values to be committed, I just don't see
> it's value.
The whole value is in waiting for the values to be committed. Without
the write barrier, this could e.g. happen:
a) in parent thread
* globalvar:=1;
* create_thread();
b) in child thread:
writeln(gobalvar); // prints 0, or whatever the value of globalvar was
before the parent thread assigned "1" to it
That can even happen on x86 in its default mode, because this is a
"Stores reordered after Loads" situation (but as mentioned below, it's
unlikely to happen).
>> And the reason that's it's probably not required, is because
>> there's so much
>> code in between that it's unlikely that any of those writes would
>> still be
>> outstanding at that point. It's not "for the few that don't
>> understand how
>> to create a thread".
>
> Exactly. The other code being what?
If you mean the "code in between" by "the other code": any code
executed between setting the global variable in the parent thread and
the actual starting of the child thread (which includes all of the
code in pthread_create, and in case of FPC in tthread.create and/or
BeginThread, although in case of tthread.create there is also some
extra communication between the parent thread and the child thread via
the heap).
Jonas
More information about the fpc-pascal
mailing list