Answer the question
In order to leave comments, you need to log in
How to work with streams correctly?
Often in my programs there are different errors. Found out that maybe I'm not working correctly with threads. In programs, I usually need to perform some actions that take 2-3 minutes. For example - reading a large file or database.
Therefore, I create 1 thread and perform all actions in it.
(The program usually consists of 1 module (1 form).)
Interested in your opinion, namely - what am I doing wrong and how to write this test case correctly.
How to work with streams correctly? Below is an example code with comments.
How do I see my code.
While the thread is running (2-3 minutes), I need to show messages to the user. At what stage the program is running. To do this, I use the Synchronize method and my Show_message procedure.
In shared variables (above implementation) I arrange variables, arrays, etc. They should be visible from anywhere in the program. Including from the stream.
Then I use these objects in any part of my program.
But since I cannot pass the parameter (message text) there, I use the output_message variable for this, to which I "assign the message text". And in procedure Show_message "I take away the text from this general variable" and I transfer to a label on the form.
Sometimes I create objects outside of the thread and use them in the thread (TStringList.Create).
Often I work with shared variables/objects in all parts of the program (my_array).
The code
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
start_thread_button: TButton;
information_label: TLabel;
procedure start_thread_buttonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
//Класс потока TMyThread
TMyThread = class(TThread)
protected
procedure Execute; override;
procedure Show_message;
end;
//Конец класса потока
var
Form1: TForm1;
//Общие переменные
MyThread: TMyThread; //Поток
output_message:string; //Переменная для передачи сообщения "на форму"
file_list:TStringlist; //Список содержащий файлы
my_array: array of array [1..2] of string; //Массив для примера
implementation
{$R *.dfm}
//Вывод сообщения
procedure TMyThread.Show_message;
begin
//Передача текста из общей переменной (своего рода буффер) на форму (в VLC компонент )
form1.information_label.Caption:=output_message;
end;
//Запуск
procedure TForm1.start_thread_buttonClick(Sender: TObject);
begin
//Создали объект вне потока TMyThread
file_list:=TStringList.Create;
//Работаем с объектом из общих переменных
SetLength(my_array, 1);
//Запускаем поток
MyThread:=TMyThread.Create(False);
end;
//Процедура потока TMyThread
procedure TMyThread.Execute;
begin
//Работаем с объектами, созданными вне потока TMyThread
file_list.Add('добавим элемент листа');
file_list.Destroy;
//Работаем с объектом из общих переменных в потоке
my_array[1,1]:='элемент массива';
//Вывод сообщения (работа с VLC должно быть синхронизировано)
output_message:='Вывод тестового сообщения в information_label на форме'; Synchronize(Show_message);
end;
end.
Answer the question
In order to leave comments, you need to log in
it is not necessary to create a global variable output_message
in Syncronize, you can pass an anonymous procedure, then the message can be stored in a local variable of the thread procedure
procedure TMyThread.Execute;
var
Msg: string;
begin
...
Syncronize(procedure() begin
Show_message(Msg);
end);
end.
file_list.Free;
// или
FreeAndNil(file_list);
While participating in the answer to the question How to fix the listerror list index out of b... wanted to suggest using a stream for a single file. Each file will be processed by a separate thread.
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
ListBox1: TListBox;
procedure Button1Click(Sender: TObject);
private { Private declarations }
public { Public declarations }
end;
var Form1: TForm1;
implementation
{$R *.dfm}
uses Unit2;
procedure TForm1.Button1Click(Sender: TObject);
var fl: String;
tr: TSome;
begin
fl := ExtractFilePath( Application.ExeName ) + GUIDToString( TGUID.NewGuid ) + '.thr';
tr := TSome.Create( fl );
ListBox1.Items.Add( fl );
end;
end.
unit Unit2;
interface
uses System.Classes, System.SysUtils;
type
TSome = class(TThread)
private { Private declarations }
FFile: String;
FMess: String;
procedure UpdateForm;
protected
procedure Execute; override;
public { Public declarations }
constructor Create( sFile: String );
end;
implementation
uses Unit1;
constructor TSome.Create( sFile: String );
begin
FFile := sFile;
inherited Create( False );
end;
procedure TSome.Execute;
var outfile: TextFile;
tr: String;
begin
while not Self.Terminated do begin
tr := IntToStr( Self.Handle ) + ' - '+ DateTimeToStr( Now ());
AssignFile( outfile, FFile );
Rewrite( outfile );
Writeln( outfile, tr );
CloseFile( outfile );
Self.FMess := tr;
Synchronize( UpdateForm );
Sleep( 1000 );
end;
end;
procedure TSome.UpdateForm;
begin
Form1.ListBox1.Items.Add( Self.FMess );
end;
end.
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question