Delphi Pages Forums  

Go Back   Delphi Pages Forums > Delphi Forum > VCL

Lost Password?

Reply
 
Thread Tools Display Modes
  #1  
Old 08-31-2015, 11:31 PM
lexd lexd is offline
Senior Member
 
Join Date: Feb 2015
Posts: 268
Default thread file access TMemorystream

I'm trying to write this stream below to use a thread to load and save files
This allows me to use two Streams and as one is loading the other is accessed by code. The question is have I used the thread correctly?
Any things of advice to improve it?

unit FileThreadMemStream;

interface

uses Classes, SysUtils, Windows, ActiveX;

type

TFileThreadMemStream = class;

TaThread = class(TThread)
private
PStream: TFileThreadMemStream;
FGoMethod: TThreadMethod;
protected
procedure GetPerantStream(Stream: TFileThreadMemStream);
procedure Execute; override;
public
constructor Create;
destructor Destroy; override;
end;

TFileThreadMemStream = class(TMemoryStream)
private
FEndedEvent: TThreadMethod;
FFile: TFileStream;
FFileName: String;
FThread: TaThread;
FStartPos,
FEndPos: Int64;
FAddOnFile: Boolean;
FFileWorkFinnshed: Boolean;
procedure Save_File;
procedure Load_File;
public
constructor Create;
destructor Destroy; override;
procedure LoadFromFile(StartPos, EndPos: Int64); Reintroduce;
//what part of file
procedure SaveToFile(Add: Boolean); Reintroduce; //add to file or
rewrite
property EndedFileEvent: TThreadMethod read FEndedEvent write
FEndedEvent;
property FileName: String read FFileName write FFileName;
Function FileWorkFinnshed: Boolean;
end;

implementation

constructor TaThread.Create;
begin
inherited Create(True);
end;


destructor TaThread.Destroy;
begin
Suspend;
WaitFor; //Wait for the process to stop before we continue freeing things...
inherited;
end;

procedure TaThread.Execute;
begin
FGoMethod;
end;

procedure TaThread.GetPerantStream(Stream: TFileThreadMemStream);
begin
PStream := Stream;
end;

{ TFileThreadMemStream }

constructor TFileThreadMemStream.Create;
begin
FThread := TaThread.Create;
FThread.GetPerantStream(Self);
FThread.FGoMethod := nil;
FFileWorkFinnshed := True;
end;

destructor TFileThreadMemStream.Destroy;
begin
FThread.Free;
inherited;
end;

function TFileThreadMemStream.FileWorkFinnshed: Boolean;
begin
Result := FFileWorkFinnshed;
end;

procedure TFileThreadMemStream.Load_File;
begin
FFile := TFileStream.Create(FFileName, fmShareDenyNone);
FFile.Position := FStartPos;
SetSize(0);
CopyFrom(FFile, FEndPos - FStartPos);
Position := 0;
FFile.Free;
FFileWorkFinnshed := True;
If Assigned(EndedFileEvent) then EndedFileEvent;
FThread.Synchronize(FThread.FGoMethod);
FThread.Suspend;
end;

procedure TFileThreadMemStream.Save_File;
begin
FFile := TFileStream.Create(FFileName, fmCreate);
If FAddOnFile then
FFile.Position := FFile.Size;
Else FFile.Size := 0;
Position := 0;
FFile.CopyFrom(Self, Self.Size);
Position := 0;
FFile.Free;
FFileWorkFinnshed := True;
If Assigned(EndedFileEvent) then EndedFileEvent;
FThread.Synchronize(FThread.FGoMethod); //stop
FThread.Suspend;
end;

procedure TFileThreadMemStream.LoadFromFile(StartPos, EndPos: Int64);
begin
FStartPos := StartPos;
FEndPos := EndPos;
FThread.FGoMethod := Load_File;
FFileWorkFinnshed := False;
FThread.Synchronize(FThread.FGoMethod);
FThread.Resume;
end;

procedure TFileThreadMemStream.SaveToFile(Add: Boolean);
begin
FAddOnFile := Add;
FThread.FGoMethod := Save_File;
FFileWorkFinnshed := False;
FThread.Synchronize(FThread.FGoMethod);
FThread.Resume;
end;

end.
Reply With Quote
  #2  
Old 09-01-2015, 12:12 AM
lexd lexd is offline
Senior Member
 
Join Date: Feb 2015
Posts: 268
Default

I do not think I need
FThread.Synchronize(FThread.FGoMethod);
In my code.

Is it just the Delphi compiler that stops the main thread while the 2nd thread does its thing.
Is it safe for a thread to stop its self like this.
Reply With Quote
  #3  
Old 09-01-2015, 12:38 PM
kolbasz kolbasz is offline
Senior Member
 
Join Date: Nov 2013
Posts: 841
Default

Hi lexd,

You only need synchronize when you want to update a visual control.

regards,
kolbasz
Reply With Quote
  #4  
Old 09-01-2015, 03:05 PM
rojam rojam is offline
Senior Member
 
Join Date: Jun 2015
Posts: 199
Default

I think you don't fully understand how threads work. While you do create your thread suspended (which has been deprecated), the first time you resume it, presumably after you set GoMethod, it completes its task and TERMINATES. When a thread is finished with its Execute method it terminates, plain and simple. If you want the thread to stick around after it finishes a task, then you need to have some kind of loop in the execute method. This way, you can still start the thread terminated (to set some variables after you create it if necessary), but then just call the thread's Start method to start the loop. You never have to suspend it resume it..

Code:
constructor TFileThreadMemStream.Create;
begin
   FThread := TaThread.Create;
   FThread.GetPerantStream(Self);
   FThread.FGoMethod := nil;
   FThread.Start;
   FFileWorkFinnshed := True;
end;
Then inside the Execute method you could possibly check some variable, accessible from your main thread, that is giving it more work to be accomplished.

Code:
procedure TaThread.Execute;
begin
   while not Terminated do
   begin
      //Check for more work
      //if given more work
         //complete new work
   end;
end;
then from the MAIN thread (or where the thread was created), you would trigger the thread to terminate, wait for it to finish, and then free the thread object, presumably when you no longer need the thread, say the TFileThreadMemStream Destroy Method, here the waitfor makes your object wait for the thread to terminate, when it returns from the waitfor, it frees the thread.

Code:
procedure TFileThreadMemStream.Destroy;
begin
    FThread.Terminate;
    FThread.WaitFor;
    FThread.Free;
    Inherited;
end;
You should have no reason to call waitfor from within the thread itself, like you do in the destructor, and you definitely do not need to call suspend in the destructor either.

Last edited by rojam; 09-01-2015 at 06:46 PM.
Reply With Quote
  #5  
Old 09-01-2015, 10:09 PM
lexd lexd is offline
Senior Member
 
Join Date: Feb 2015
Posts: 268
Default

Ok I get your correction in the Destroy method
Good point

But I do not need the loop to do work?
I just need to load the file and it self Suspends its self

testing looks good as it copys files and saves them to other locations
Reply With Quote
  #6  
Old 09-01-2015, 10:35 PM
rojam rojam is offline
Senior Member
 
Join Date: Jun 2015
Posts: 199
Default

Quote:
But I do not need the loop to do work?
I just need to load the file and it self Suspends its self
I think you miss the point. If you don't do the loop there won't be anything left to suspend. The thread will have already terminated. The variable you use to create the thread will still point to the thread, but the thread will have already executed, run the destructor, and no matter what else you do with it, it is just not going to do anything.

The Execute Method only executes once.
Reply With Quote
  #7  
Old 09-01-2015, 10:52 PM
lexd lexd is offline
Senior Member
 
Join Date: Feb 2015
Posts: 268
Default

Are you saying I should have a loop in my code rather than use the end statement in my procedure to be safe. Is that what you are saying.

I do not want to use termite, because termite sets up and drops 1 megabyte of data that takes way too much time. Suspend means 1 megabyte is held at all times but things are fast acting. I hope you can see this point.
Reply With Quote
  #8  
Old 09-01-2015, 10:56 PM
lexd lexd is offline
Senior Member
 
Join Date: Feb 2015
Posts: 268
Smile

I had been relying on Synchronize to reset where the code restarts.
And that's not good you say. I see the point now.
Reply With Quote
  #9  
Old 09-02-2015, 01:27 PM
rojam rojam is offline
Senior Member
 
Join Date: Jun 2015
Posts: 199
Default

Quote:
I do not want to use termite, because termite sets up and drops 1 megabyte of data that takes way too much time
No, you only use terminate when you no longer need your TFileThreadMemStream class. You don't even have to use suspend. Your thread will simply keep polling within the while loop if your TFileThreadMemStream has given it another task, if it hasn't, sleep (maybe for 1 second), and then poll again or if it has, accomplish the requested task, then back to sleep and poll again. You may want to look at a thread safe queue as a means to pass information safely to your thread. Don't know which version of Delphi you are using, but if it supports generics, then I would suggest you use the generic.

Code:
procedure TaThread.Execute;
begin
   while not Terminated do
   begin
      //if given task then
        //Perform task
      sleep(1000);
   end;
end;
That way, you create your thread suspended, set your thread variables, start it, then you give it tasks to accomplish, then when you destroy your TFileThreadMemStream class, terminate the thread like I showed in the previous post.

Quote:
I had been relying on Synchronize to reset where the code restarts.
Synchronize has no means to reset the thread at a given point, it simply schedules a task with the main thread for the main thread to accomplish. And as I mentioned, without a loop in your execute, the thread when created/started, ran through the execute (once), ran the destructor, and that was it. No calls to that instance of the thread was ever going to do anything for you. It had finished.

Last edited by rojam; 09-02-2015 at 01:35 PM.
Reply With Quote
  #10  
Old 09-02-2015, 10:33 PM
lexd lexd is offline
Senior Member
 
Join Date: Feb 2015
Posts: 268
Default

So I cannot replace sleep with with suspend
I think that is not true in reality as I test it
And its a pain to the object should I only need a simple read of the stream and reload more data
Reply With Quote
Reply

Tags
delphi 7, thread

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 11:23 PM.


Powered by vBulletin® Version 3.8.8
Copyright ©2000 - 2019, vBulletin Solutions, Inc.