![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Многопочность при работе с портами ПК [D6, WinXP]
Gugle © (2005-10-17 12:26:00)Доброго времени суток!
Столкнулся с некоторыми проблемами при работе с многопоточностью. Много потоков создаю при работе не с файлами, а с различными портами ПК. Программа постоянно что передает и принимает от удаленных устройств и если делать все в одном потоке она постоянно висит (т.е. занята), в определенные промежутки времени (решает пользователь) необходимо прервать тот или иной поток!
Создаю отдельный класс (TMyThread = class(TThread)). Делаю в нем несколько процедур и запускаю его отдельным потоком (MyThread:=TMyThread.Create(False)) и потом пытаюсь этот поток прервать (MyThread.Free).
Что вижу:
1. Проседура (procedure Execute; override) внутри которой происходят основные вычисления вроде как останавливается, однако память она продолжает забивать (видимо поток внутри памяти продолжает пахать).
2. Процедуры и функции вне (procedure Execute; override) работают хоть и последовательно, но не внутри самого потока и для них выделяется память отдельно (вообще такое ощущение что запускается в потоке не весь класс, а просто "procedure Execute".
3. При попытке остановки потока (MyThread.Free) память не освобождается и мало того программа основного потока занята темы процедурами и функциями которые находятся вне "procedure Execute", но в самом классе ТMyThread, с чего вдруг непонятно?!?
Теперь вопросы:
1. Работа отдельно потока запущеного через отдельный класс происходит ТОЛЬКО в "procedure Execute" или нет?
2. Как, не только отпустить поток, но и освободить память которая была выделана под этот поток?
3. Если на первый вопрос "Да", то как остановить работу всего класса и вообще возможно это или нет?
Не уверен что нужен код самой программы поэтому кину программу на которой тестирую эти потоки:
(Он сильно урезан от основного кода и тут работа только с одним COM-портом. Процедуры иниациализации потра и определения его параметров думаю ненужны, но они есть и выполняются не в классе ТMyThread, а в основном потоке)
По программе:
Unit1:
1. Есть форма на ней пару кнопок. Button1 - запускает дополнительный поток, Button2 - останавливает его.
2. В Edit1 и Edit3 - вывод результатов математических вычислений из разных мест программы и разными методами. Edit2 - нужен для того, что бы быть уверенным что при запуске дополнительного потока, основной не занят.
procedure TForm1.Button1Click(Sender: TObject);
begin
StartThrd;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
StopThrd;
end;
Unit2:
Собственно тут и реализован отдельный класс и его работа.
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,Unit1;
type
TMyThread = class(TThread) //Новый класс
procedure ShowResult;
private
answer: Integer;
protected
Procedure WriteStrToPort;
procedure Execute; override;
end;
var MyThread:TMyThread;
answer: Integer;
procedure StartThrd;
Procedure StopThrd;
implementation
procedure TMyThread.ShowResult;
begin
Form1.Edit1.Text := IntToStr(answer);
end;
procedure TMyThread.Execute;
var
i: Integer;
begin
for i := 1 to 100000 do
begin
answer := answer + 1;
// MyThread.ShowResult;
// MyThread.WriteStrToPort;
Form1.Edit3.Text := IntToStr(answer);
Synchronize(WriteStrToPort);
Synchronize(ShowResult);
end;
end;
Procedure TMyThread.WriteStrToPort;
Var
MyBuff: Array[0..1023] Of Char;
ByteWritten, ByteReaded: Cardinal;
DataFull : String;
hPort:Integer;
Begin
DataFull := IntToStr(answer);
FillChar(MyBuff,SizeOf(MyBuff),#0); //готовим буфер для передачи
DataFull:=DataFull;
StrPCopy(MyBuff,DataFull); //передаем данные в буфер
WriteFile(hPort,MyBuff,Length(DataFull),ByteWritten,Nil); //передаем данные
// Читаем буфер из com-порта
FillChar(MyBuff,SizeOf(MyBuff),#0);
ReadFile(hPort,MyBuff,SizeOf(MyBuff),ByteReaded,Nil);
end;
procedure StartThrd;
begin
MyThread:=TMyThread.Create(False);
If MyThread = Nil Then
Begin {Nil}
//ошибка, все выключаем и выходим
SysErrorMessage(GetLastError);
Exit;
End; {Nil}
end;
procedure StopThrd;
begin
MyThread.Free;
end;
end.
Ну, вот собственно и все. Заранее всем благоданет!
Leonid Troyanovsky (2005-10-17 14:36:00) [21]
> Gugle © (17.10.05 14:08) [6]
> Digitman © (17.10.05 13:02) [5]
> Спасибо!
Можно нескромный вопрос?
А почему "спасибо" только уважаемому Digitman © ?
И только за (17.10.05 13:02) [5] ?
Т.е., про остальное не стоило и спрашивать?
--
Regards, LVT.
Gugle (2005-10-17 14:08:00) [22]
Digitman © (17.10.05 13:02) [5]
Спасибо!
Digitman (2005-10-17 13:02:00) [23]
> Gugle © (17.10.05 12:52) [4]
> почему Synchronize не использовать?
никто не запрещает его использовать.
просто нужно хорошо понимать, что при этом происходит, и использовать этот метод в действительно необходимых и логически оправданных случаях
Gugle (2005-10-17 12:52:00) [24]Хм...
Ну по поводу
Form1.Edit3.Text := IntToStr(answer);
и
MyThread = Nil
согласен!
А почему Synchronize не использовать? (Если конечно это можно объяснить в краце или просто поверить профи?)
Fay (2005-10-17 12:46:00) [25]2 REA (17.10.05 12:39) [2]
>> 2) Synchronize не рекомендую использовать в потоках
Почему?
REA (2005-10-17 12:39:00) [26]1) внутри потока надо постоянно проворять свойство Terminated и выходить при true
2) Synchronize не рекомендую использовать в потоках
3) MyThread = Nil. Это как?
4) Form1.Edit3.Text := IntToStr(answer); - вот этого не надо делать
5) Synchronize(WriteStrToPort) - и этого
Digitman (2005-10-17 12:36:00) [27]для начала убери серьезную допущенную тобой ошибку, связанную с обращением к Form1.Edit3.Text в доп.потоке