Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2005.11.06;
Скачать: [xml.tar.bz2];

Вниз

Многопочность при работе с портами ПК   Найти похожие ветки 

 
Gugle ©   (2005-10-17 12:26) [0]

Доброго  времени суток!
Столкнулся с некоторыми проблемами при работе с многопоточностью. Много потоков создаю при работе не с файлами, а с различными портами ПК. Программа постоянно что передает и принимает от удаленных устройств и если делать все в одном потоке она постоянно висит (т.е. занята), в определенные промежутки времени (решает пользователь) необходимо прервать тот или иной поток!

Создаю отдельный класс (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.


Ну, вот собственно и все. Заранее всем благоданет!


 
Digitman ©   (2005-10-17 12:36) [1]

для начала убери серьезную допущенную тобой ошибку, связанную с обращением к Form1.Edit3.Text в доп.потоке


 
REA   (2005-10-17 12:39) [2]

1) внутри потока надо постоянно проворять свойство Terminated и выходить при true
2) Synchronize не рекомендую использовать в потоках
3) MyThread = Nil. Это как?
4) Form1.Edit3.Text := IntToStr(answer); - вот этого не надо делать
5) Synchronize(WriteStrToPort) - и этого


 
Fay ©   (2005-10-17 12:46) [3]

2 REA   (17.10.05 12:39) [2]
>> 2) Synchronize не рекомендую использовать в потоках
Почему?


 
Gugle ©   (2005-10-17 12:52) [4]

Хм...

Ну по поводу
Form1.Edit3.Text := IntToStr(answer);
и
 MyThread = Nil
согласен!

А почему Synchronize не использовать? (Если конечно это можно объяснить в краце или просто поверить профи?)


 
Digitman ©   (2005-10-17 13:02) [5]


> Gugle ©   (17.10.05 12:52) [4]


> почему Synchronize не использовать?


никто не запрещает его использовать.

просто нужно хорошо понимать, что при этом происходит, и использовать этот метод в действительно необходимых и логически оправданных случаях


 
Gugle ©   (2005-10-17 14:08) [6]


Digitman ©   (17.10.05 13:02) [5]


Спасибо!


 
Leonid Troyanovsky ©   (2005-10-17 14:36) [7]


> Gugle ©   (17.10.05 14:08) [6]

> Digitman ©   (17.10.05 13:02) [5]

> Спасибо!


Можно нескромный вопрос?
А почему "спасибо" только уважаемому Digitman © ?
И только за  (17.10.05 13:02) [5] ?
Т.е., про остальное не стоило и спрашивать?

--
Regards, LVT.


 
Digitman ©   (2005-10-17 14:46) [8]


> Leonid Troyanovsky ©   (17.10.05 14:36) [7]


Лёнь, ты б намекнул что ли уж ув.коллеге Gugle про остальное ... И тебе бы приятно было (даже абы память свою освежить), и ему пользительно ..


 
Evgeny V ©   (2005-10-17 15:18) [9]


> 3. При попытке остановки потока (MyThread.Free) память не
> освобождается и мало того программа основного потока занята
> темы процедурами и функциями которые находятся вне "procedure
> Execute", но в самом классе ТMyThread, с чего вдруг непонятно?
> !?


У вас так написано, разберитесь с Synchronize
Код работы с портом мне показался странным, если я ничего не пропустил. Я не увидел где переменная hport получает верное значение порта или какой-либо хэндл?
Совет - Поищите статьи по работе с портом на королевстве дельфи, там были, почитайте еще про работу с потоками, уточните для себя, что такое Synchronize


> 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;


 
Leonid Troyanovsky ©   (2005-10-17 15:23) [10]


> Digitman ©   (17.10.05 14:46) [8]

> Лёнь, ты б намекнул что ли уж ув.коллеге Gugle про остальное
> ... И тебе бы приятно было (даже абы память свою освежить),
>  и ему пользительно ..


Уже, считай, намекнул :)
Просто, заметно, что коллега долго варился в своем соку, а значит
свежие впечатления могут быть не всегда могут быть с пользой усвоены.

Ну, а чтобы быть невежливым по отношению к автору (да простит
он нам его обсуждение в третьем лице):

2Gugle ©:

RTFM (не знаю, все ли ссылки еще живы):

Tutorial on thread programming in Delphi:

http://www.pergolesi.demon.co.uk/prog/threads/ToC.html
http://www.sklobovsky.com/community/threadmare/threadmare.htm

Handling exceptions in a thread:
http://community.borland.com/article/0,1410,10452,00.html

by Tolik Tentser:

http://www.compress.ru/Article.asp?id=2164

Насчет того, что значит "пересинхронизировать", наверное,
это к Чарли Калверту "Дельфи Х. Энциклопедия пользователя".

--
Regards, LVT.


 
Gugle ©   (2005-10-17 16:26) [11]

Всем спасибо!
По поводу Synchronize разобрался... Каюсь повтыкал туда куда не надо было! "Чайники" и "кофейники" были и будут.

Извините кого обидел не сказав "Спасибо".
Digitman   Спасибо!
REA   Спасибо!
Fay   Спасибо!
Leonid Troyanovsky   Спасибо!
Evgeny   Спасибо!

Вроде никого не забыл!

Evgeny По поводу hPort я написал что все его скрипторы, дескрипторы и т.д. и т.п. я определяю, но во избежании нагроможденности кода сюда запихивать не стал да и вопрос был не в этом!

Кстати товарищи, вопросик по очистки памяти остался открытым, поток хоть и останавливается, но из памяти не выбрасывается. У кого на компе 512 оперативочки и выше тому это конечно побарабану (На маей машине поболе чем 512 и мне это то же дофени). Однако есть ПК где оперотивочки 64 и там то нужен каждый килобайтик! Именно поэтому то я и задаюсь этой проблемой. Ну а как "учат" большинство книг (и не только) несмотря ни на что следить за тем сколько памяти забивает прога всетаки желательно.


 
Gugle ©   (2005-10-17 16:28) [12]

Всем спасибо!
По поводу Synchronize разобрался... Каюсь повтыкал туда куда не надо было! "Чайники" и "кофейники" были и будут.

Извините кого обидел не сказав "Спасибо".
Digitman   Спасибо!
REA   Спасибо!
Fay   Спасибо!
Leonid Troyanovsky   Спасибо!
Evgeny   Спасибо!

Вроде никого не забыл!

Evgeny По поводу hPort я написал что все его скрипторы, дескрипторы и т.д. и т.п. я определяю, но во избежании нагроможденности кода сюда запихивать не стал да и вопрос был не в этом!

Кстати товарищи, вопросик по очистки памяти остался открытым, поток хоть и останавливается, но из памяти не выбрасывается. У кого на компе 512 оперативочки и выше тому это конечно побарабану (На маей машине поболе чем 512 и мне это то же дофени). Однако есть ПК где оперотивочки 64 и там то нужен каждый килобайтик! Именно поэтому то я и задаюсь этой проблемой. Ну а как "учат" большинство книг (и не только) несмотря ни на что следить за тем сколько памяти забивает прога все-таки желательно.


 
Evgeny V ©   (2005-10-17 16:42) [13]

У вас возможна ситуация, что вы закрываете поток, но поток не закончил операцию чтения из порта и висит. Операция эта  у вас синхронная, как настроены тайм-ауты для операций чтения и записи порта в коде не показано, возможно причина в этом. Без кода конечно трудно понять, что и как.
Вообще я сам работаю чаще с COM портами и предпочитаю асинхронную работу с ними - кода надо написать больше, больше проверок но проще и оперативней в итоге логика работы и взаимодействия в другими потоками - но это мое мнение и тут у каждого свое видение.


 
Gugle ©   (2005-10-17 17:14) [14]

to [Evgeny V]

  Хм... Интересное предположение.
Вообще то я работаю с синхронной передачей через COM-порты, но в эту работу иногда вклиниваются и асинхронные посылки данных (с выделением соответствующего потока, ну там с учетом избыточности и многих других интересных настроекк порта). Просто еслия это все выкину товозникнут вопросы по самой настройки портов, как формируются посылки моменты вкл. асинхронного потока и выключение его, избыточность, а по какому "закону" это туда вклинивается и т.д. ...  Да и код этот выглядит ОГОГО каким, т.к. работаю сразу с несколькими COM-портами, да и подключено еще не по одному устройству к каждому порту. К тому же все уже вынесено в собственные библиотеки и ковырять их, если сказать по совести, неохото выкидывая кучу всякого хлама что бы код программы более-менее был читабельным... Да и тут я выкинул все свои проверки на ответы устройств!

 Как я полагаю если поток стоит, например, в режиме Sleep(1000) то при попытке остановки потока сначала должна выполнится сама функция Sleep(1000) до конца и уже потом прерваться поток.


 
REA   (2005-10-17 17:25) [15]

По поводу работы с портами - рекомендую изучить готовые компоненты - можно обнаружить массу полезной информации.
Куда девается память по этому коду пожалуй не сказать да и вообще это зависит от того, как измеряется объем свободной памяти.
Зачем для работы с портами делать много потоков (больше, чем самих портов) не совсем понятно.


 
Gugle ©   (2005-10-17 17:50) [16]

Один поток на один COM-порт. Так и делается!
Почему встал вопрос с памятью:
В основной программе работа ведется сразу (как min) с 4 портами.
Если передавать не только синхронную информацию, но и асинхронную и при этом получать информацию от удаленных устойств, обработывать ее, кидать что то на экран пользователью, отработывать все ошибки связаные с самой программой, отработывать ошибки в канале связи (т.к. это только в домашних условиях там чистота и порядок), одновременно готовить данные для синхронной и асинхронной передачи и при этом переключать сам порт в разные режимы работы, следить за тем какое устройство отвечает и кокой ей нужен канал связи (RS-232 или RS-485) и с какими настройками этот канал и еще много и МНОГО всякого бреда выполнять... То такой поток у меня занимает около 30 000 KB - как говорит "Диспечер задач Windows". Это ОДИН поток для ОДНОГО com-потра.
Теперь их 4. (Т.к. прогу использовать для меньшего числа потоков нецелесообразно, специфика работы как программы так и того для чего она создается).
Плюс память на всякие открытые формы и т.д.
Вытекает что памяти надо довольно много и тут один такой поток остановился, но память не "выгрузил".... Накладно как то...  А если портов будет немного больше чем 4.

Вот отсюда вытек вопрос о памяти.


 
REA   (2005-10-17 18:07) [17]

а не систему сбора и обработки информации делаете?


 
Evgeny V ©   (2005-10-18 08:51) [18]

У меня подозрение, что мы немного о разном говорим. Под словом асинхронная работа с портом (кстати количество портов значения не имеет, и я так же реализую схему один порт один поток) - я имею ввиду работу в OVERLAPPED режиме. То есть при открытии порта CreateFile указываю  флаг FILE_FLAG_OVERLAPPED и соответственно вам надо тогда почитать ReadFile, WriteFile, как с ними работать в этом режиме. Так же использую и WaiCommEvent и WaitForMultipleObjects функции, но это дело написания программы. Можно работать и в синхронном режиме, как у вас, просто надо закрыть порт, возможно использовать СancelIO функцию, для завершения работы функций, ожидающих операции ввода выода, что даст потоку возможность работать. Но это все предположения, так как не видно того как инициализирован порт у вас, как идет работа цикла в потоке, тот код который вы привели слишком схематичен. Кстати прислушайтесь и к REA   (17.10.05 17:25) [15], есть много хороших компонентов под дельфи для работы с COM портами, что может облегчит Вам задачу


 
Alex Konshin ©   (2005-10-18 13:08) [19]

Добрый совет: почитай MSDN про методы синхронизации потоков и используй функции WaitFor*. И жди порты этими функции. И забудь о функции Sleep, используй те же самые WaitFor* с таймаутом и обязательно с доплнительным event, который создан специально для прерывания ожидания, чтобы можно было корректно завершить поток.


 
han_malign ©   (2005-10-18 14:17) [20]


> но память не "выгрузил"

- откуда и какую? Конкретный экземпляр MyThread: TMyThread - от силы, пару десятков байт отъедает. Или ты хочешь еще и код выгружать? И как ты это определяешь - через System.AllocMemSize, или через Task manager?


 
Gugle ©   (2005-10-18 18:23) [21]

to > REA
   Я бы так не сказал, хотя это то же там присутствует.

to > Evgeny V
   Вы правы, говорим о разном...

to > han_malign
   Тот "MyThread" который я выкинул в самом начале вопроса точно занимает несколько байт, но это прога проверочная. В основной все сложнее и там много чего происходит (не в этом суть). Думаю что сам код (Если я правильно понял, что Вы имеете ввиду, то это Unit) не занимает много памяти. При выполнение "MyThread.Free" происходит "как бы" обрыв связи основной проги с потоком "MyThread", т.е. программа с ним не работает, а в памяти (в оперативке) всеравно продолжается выполнение этого потока. А мне нужно остановить выполнение потока, а не "оборвать взимодействие" с ним. Точнее объяснить не могу!

  P.S. Процессы в памяти смотрю через стороние программы! То же самый SiSoft может это делать. Покопаться надо только у него в настройках.


 
Evgeny V ©   (2005-10-19 09:38) [22]

Советы уже были, но еще раз, поробуем с другого конца - первое, уверены ли вы, что потока продолжает работу? Если да, вставьте диагностику, типа вывода в Мемо на главной форме (конечно используя синхронизацию, Synchronize например) Читаю , Передаю, Завершаю работу  -вам виднее какие сообщения и где надо вставить. Что бы видеть, в какой части кода поток находится, на выполнении какой команды он висит(если такое происходит).
Определите что происходит, найдите причину этого. Первое что пришло мне в голову, я уже говорил, выполнение синхронных операций ( у вас не OVERLAPPED чтение и запись), а таймаут на операции настроен на бесконечное ожидание,так же могут сказаться и  линии управления потоком данных CTS или DSR, если вы используете их состояние в ваших настройках порта или в своей программе, но это из серии гадания, я не знаю ваших настроек порта, не знаю что происходит. Попробуйте найти, отладчик или диагностические сообщения вам помогут, тогда может вы и сами найдете как сделать то, что вы хотите. В любом случае, зная конкретную причину, того что происходит, другим легче будет дать совет.


 
Alex Konshin ©   (2005-10-19 11:06) [23]

Еще совет: чтобы при выдаче отладочных сообщений не заморачиваться с синхронизацией используй функцию OutputDebugString (еще называют ODS). Смотри выводимые сообщения в каком-нибудь вьюере ODS. Например, в том же Delphi IDE есть такой. Но я бы все равно порекомендовал DebugView с сайта http://www.sysinternals.com/ , т.к. он еще умеет смотреть ODS удаленно.


 
REA   (2005-10-19 11:35) [24]

2Alex Konshin ©   (19.10.05 11:06) [23]
А сохранять логи умеет? А то я тут мучаюсь частенько, если нужно что-то в тундре отладить - испорченный телефон буквально получается.


 
WondeRu ©   (2005-10-19 11:42) [25]

Alex Konshin ©   (19.10.05 11:06) [23]
OutputDebugString

почему-то данная функция (вернее частый ее вызов) здорово тормозила мою программу :(
в делфовском дебагере вообще жуть тормозная получается...


 
Gugle ©   (2005-10-19 11:55) [26]

Принял к сведению все советы!

Всем огромное спасибо.


 
Alex Konshin ©   (2005-10-19 13:07) [27]

WondeRu ©   (19.10.05 11:42) [25]
>Alex Konshin ©   (19.10.05 11:06) [23]
>OutputDebugString
>почему-то данная функция (вернее частый ее вызов) здорово тормозила мою программу :(
>в делфовском дебагере вообще жуть тормозная получается...

Так функция-то отладочная, ей в принципе необязательно работать быстро.
Да, она действительно тормозит. Но зато проста в использовании. Единственной более-менее приемлемой альтернативой я вижу только асинхронную запись в файл, но сделать это равильно не так уж и просто и новичку будет просто не по зубам.



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2005.11.06;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.56 MB
Время: 0.067 c
4-1125311994
ANB
2005-08-29 14:39
2005.11.06
Как включить верхний регистр в чужом процессе ?


2-1129364731
Vital
2005-10-15 12:25
2005.11.06
не используя OnPaint


8-1118551920
GekaNaz
2005-06-12 08:52
2005.11.06
отображение подгружаемых картинок


14-1129636023
Stranger53
2005-10-18 15:47
2005.11.06
Новые версии Delphi


14-1129612855
Ega23
2005-10-18 09:20
2005.11.06
Interpolitex-2005 Кто пойдёт?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский