Recent

Author Topic: Freeing resources, making sure they aren't being used by other units?  (Read 4863 times)

dieselnutjob

  • Full Member
  • ***
  • Posts: 224
I'm having a bit of trouble with a complex program that I've been writing for some time.
There is a gui thread, and a control thread which sends commands to and receives responses from an external device.
There are therefore packets that get sent to the device, and packets that are waited for (with timeouts) and processed.
As I'm not a fantastic programmer I tend to use simple variables, strings, records etc for most stuff, but as there packets are begin passed between so many different units for different layers of the various protocol stacks I thought that this would be one area where it would be a really good idea to create a record and just pass pointers to the record around so that as it gets processed the actual packet doesn't constantly get moved around.

So, when a user clicks on something that starts the process it's easy enough because the main control unit can "new(myrecord)" and then that can be used for the current send/receive packet etc. and then kick off the right bit of code to do the thing that the user requests.

The problem come when the user wishes the process to stop.

The control unit can set a variable "running" in the packet handling unit (these are in the same thread) and this so stuff in the packet handling unit works

Code: [Select]
got_packet:=false;
repeat
  check_for_a_packet(fpmyrecord)); //gets a packet, puts it in the record, sets got_packet
  timeout:=check_the_clock(maxtime);
  poll_control(10);
until got_packet OR timeout OR (NOT running);
if got_packet then process_packet(fpmyrecord);

the poll_control(10) is a critical part of the code.
it behaves like sleep(10) but instead of doing nothing it runs a bunch of central loops that run some
every1ms
every10ms
every100ms

procedures

every single loop in the entire project uses poll_control(number) so that the control unit can check for user input and maintain stuff that it needs to etc

Now this is my problem;
in the main control unit I have a procedure that runs if the user clicked stop, or the program wants to close or something
Code: [Select]
procedure TControl.start;
begin
  new(myrecord);
  PacketCode.Create;
  PacketCode.pmyrecord:=myrecord;  //sets fpmyrecord in the packetcode
  PacketCode.Start;
  PacketCode.Running:=true;
end;

procedure TControl.stop;
begin
  PacketCode.Running:=false;  //property that tells PacketCode to quit any repeat until loops
  PacketCode.Terminate;
  dispose(myrecord);
end;

The problem is that I guess that if my repeat until loop accessed fpmyrecord after the "dispose" has run but before the "until (NOT running)" then I get a seg fault or something.

I suppose that I could create a readable property such as PacketCode.Finished and set it and the end of every loop with a
if NOT running then fFinished:=true;

then do
repeat
  sleep(1);
until PacketCode.Finished;

before the dispose

but I'm just wondering if my whole idea is wrong and if there is a standard and better way to do this kind of thing

any comments gladly received.
« Last Edit: July 20, 2010, 10:57:31 am by dieselnutjob »

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2622
is tcontrol a thread ? then you can use tcontrol.waitfor
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

dieselnutjob

  • Full Member
  • ***
  • Posts: 224
I tried that but it wouldn't compile.
The reason (I think) is that tcontrol is calling routines from the packetcode unit directly and therefore they are in the same thread.

garlar27

  • Hero Member
  • *****
  • Posts: 652
Maybe you can use a counter, so each time a thread or method is using the record, it  increases the counter by 1 and decreases it when is not needed (try ... finally is recomeded).
when the program is stoping you can do something like this:
Code: [Select]
procedure TControl.stop;
begin
  PacketCode.Running:=false;  //property that tells PacketCode to quit any repeat until loops
  PacketCode.Terminate;
  repeat
    Application.ProcessMessages;
  until (MyRecordCounter < 1) or ({check timeout});
  dispose(myrecord);
end;

Remember that is recomended the use of threadvar and CriticalSection or Sinchronize when working with threads (there's a lot of info in the wiki http://wiki.freepascal.org/Multithreaded_Application_Tutorial).

dieselnutjob

  • Full Member
  • ***
  • Posts: 224
Re: Freeing resources, making sure they aren't being used by other units?
« Reply #4 on: September 01, 2010, 05:19:25 pm »
I think that what I am going to do is new(myrecord) in both the gui thread and in the control thread.

When the gui thread wants to start the control thread it will set PacketCode.pmyrecord:=myrecord

When the gui thread wants to stop the control thread the stop code will set pmyrecord to whatever it was originally

I know that it wastes memory equal in size to one record but it least if there is some loop still running somewhere it will write data to a safe place.

 

TinyPortal © 2005-2018