Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Зачем-то глючат нити... Хотя не должны... [D6, Win2k]


Страницы:   1 2

alxx ©   (2002-06-21 10:25:00) 

У меня на форме лежит Memo1. При изменении его (OnChange) у меня запускается Thread и делает кой-какую работенку - допустим считает до десяти тысяч. И вот она - эта программа виснет примерно на 1 из 100 нажатий на клавишу в Memo1 (Access violation error). Кто-нибудь может мне помочь, а то у меня уже крыша едет, чего только не перепробовал. Исходники здесь:


Const WM_ProcessDONE = wm_User+0;

type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure OnProcessDone(Var msg:TMessage); message WM_PROCESSDONE;
procedure Memo1Change(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
Running :Boolean;
NeedToRun:Boolean;
Expr :String;
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

Function ThreadFunc(P:Pointer):LongInt; stdcall;
Var
i: INteger;
DC:HDC;
S:String;
Begin
/////////////////////////////////
DC:=GetDC(Form1.Handle);
for i:=0 to 10000 do
Begin
s:=intToStr(i);
TextOut(DC,10,10,PChar(S),Length(S));
End;
ReleaseDC(Form1.Handle,DC);
//////////////////////////////////
Form1.Running:=False;

// PostMessage(Form1.Handle, WM_PROCESSDONE,0,0);
End;

procedure TForm1.FormCreate(Sender: TObject);
begin
Running:=False;
NeedToRun:=False;
end;

procedure TForm1.OnProcessDone(Var msg:TMessage);
var hThread:THandle;
ThreadID:DWord;
Begin
if Form1.NeedToRun Then
Begin
If not Running Then
Begin
hThread:=CreateThread(nil,
0,
@ThreadFunc,
nil,
0,
ThreadID);
Running:=True;
NeedToRun:=False;
End;
End;
End;



procedure TForm1.Memo1Change(Sender: TObject);
var hThread:THandle;
ThreadID:DWord;
Expr1:String;
i:Integer;
begin

Expr1:="";
For i:=0 to RE.Lines.Count-1 do Expr1:=Expr1+RE.Lines.Strings[i];
If Expr1<>Expr Then
Begin
Expr:=Expr1;
If not Running Then
Begin
hThread:=CreateThread(nil,
0,
@ThreadFunc,
nil,
0,
ThreadID);
SetThreadPriority(hThread,THREAD_PRIORITY_BELOW_NORMAL);
Running:=True; {}
End Else NeedToRun:=True;
End;
{}
end;


kull   (2002-06-24 13:32:00) [1]

Краткость - сестра таланта.


Digitman   (2002-06-24 12:53:00) [2]

>kull

Да ! Именно ! В ряде случаев диспетчеризация и кэширование потоков дает заметный выигрыш в производительности, не говоря уже об упрощении отладки в мультипоточной среде. Я ни в коем случае не утверждаю и не настаиваю, что такую организацию управления потоками нужно вставлять везде где ни попадя, но в данном конкретном случае (подстрочная интерпретация) я бы эту организацию применил обязательно.

А насчет упомянутого тобой Delphi IDE (да и не только) смею заметить, что число тех самых потоков IDE-процесса, которые ты рассматривал в "лупу" TaskMamager"а (или чем-то там еще - не знаю), непрерывно меняется, некоторые потоки могут настолько быстро стартовать/отработать/завершиться, что при той периодичности, с которой твоя "лупа" выполняет snaphot (+ задержка на его визуализацию), ты этого просто не заметишь.


kull   (2002-06-24 11:22:00) [3]


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


Да что ты!?
А я и незнал, что в этой ветке кеширование потоков разбирается, похоже я перепутал тему...

А! Да! Точно.
Здесть без ентого кеширования и необойтись.
Прийдется автору поиметься...


catalogoanatom   (2002-06-24 10:52:00) [4]

А кто будет ExitThread выполнять ???


Zemal   (2002-06-24 09:43:00) [5]

Хочешь хороший совет?! Найди библиотеку Gala и пользуйся на здоровье! В делфях нити отстой, а эта библиотека позволяет использовать всю мощь потоков в Win32. Вещь рульная!!! Сам недавно нашол и просто без ума от неё :)... влюбился :) гы-гы... недавно написал прогу в которой запускаю 800-1000 нитей и мой пенёк третий тянет лишь едва заметно подтормаживает. Короче эта библиотека позволяет обмениваться данными потокам между собой и VCL процессом, посылать сообщения форме и т.д. Полное описание на русском, куча примеров различных вариантов процессов... Короче эта библиотека инкапсулирует мьютексы, семафоры и т.д., и имеет кучу хороших процедур и функций. Это просто рулеззз! Кому надо пришлю по почте. Пишите: zemal@rtsnet.ru


Digitman   (2002-06-24 08:48:00) [6]

>kull
>>"..процесс среды Delphi: потоков раз, два и обчелся..."

И что ? Что этим ты сказать-то хотел ?
Какое это имеет отношение к теме ? Мы здесь говорим о механизме кэширования потоков, о его необходимости в ряде случаев, а не об IDE !


alxx   (2002-06-22 11:12:00) [7]

О-О-О!....

О-О-О!....

Я балдею...

Народ! Я тут сделал с одним потоком, который все время работает и при изменении строк начинает считать. Без всяких вспомогательных потоков.

Все отлично работает. Спасибо за ответы.

Теперь спать спокойно буду.


kull   (2002-06-22 02:00:00) [8]

Никуда не надо залезать.
Просто посмотреть любой утилитой, которая показывает процессы и их потоки, на процесс среды Delphi: потоков раз, два и обчелся...


Digitman   (2002-06-21 18:44:00) [9]

>kull

Еще как "извращается" !
Залезь-ка в реализацию TClientServerThread.KeepInCache да посмотри, что же это за кэш такой у "извращенцев" из Борланда непонятный ... да поинтересуйся творящимся в классе TServerWinSocket, где, собственно, кэш потоков (по необходимости) создается и контролируется в режиме stThreadBlocking ... и посмотри еще, позволительно ли клиентским потокам завершаться без ведома стартующего их и контролирующего их объекта.


kull   (2002-06-21 17:42:00) [10]

То что у тебя есть такой софт - это еще не показатель, что надо так писать.

Даже такой монстр как Delphi так не извращается.


Fiend   (2002-06-21 17:23:00) [11]

>kull Да ничё Дигитман не накрутил, ничего монстрического в том нет
У меня от есть софт в котором такое используется. Очень мило работает


kull   (2002-06-21 16:45:00) [12]


> Digitman © (21.06.02 14:14)

И я к тому же не это имел в виду, а то, что можно пользоваться потоком создавая его, разрушая на OnTerminate, и снова разрушая не боясь "холодного" старта (...зависит от объема обрабатываемых данных).


kull   (2002-06-21 16:40:00) [13]


> Digitman © (21.06.02 14:14)


Ну накрутил...
Помоему полное словоблудие...
Какие-то родительские потоки, дочерние, да где ты такого монстра видел?


alxx   (2002-06-21 14:43:00) [14]

> Digitman

Да, я попробую один поток с сообщениями. Совет полезный.
Спасибо.

А объем данных там небольшой...
Однако, почему так не работает? Ведь должна вроде...
А вообще если так получится, то и ну ее...


Digitman   (2002-06-21 14:14:00) [15]

>kull
Так а что мешает в доп.потоке стартовать дочерние ему (зависимые) доп.потоки при возникновении необходимости ? Здесь важно, чтобы каждый порожденный тем или иным доп.поток не сам себя терминировал, а завершался по команде "родителя" (родит.объект ответственен за "жизнь и смерть" дочернего), а кто кому есть "родитель" и необходимость "родов" - определяется уже требуемой логикой сложности и уровня вложения зависящих от контекста подпрограмм механизма парсинга/интерпретации


kull   (2002-06-21 13:53:00) [16]


> Digitman © (21.06.02 13:45)


Да согласен, лучше использовать один поток.
Хотя зависит от объема обрабатываемых данных.


Digitman   (2002-06-21 13:45:00) [17]

Вообще-то, если ты хочешь реализовать некий интерпретатор (или - в целом - подстрочный парсер/анализатор текста), немедленно реагирующий на любое изменение в исх.тексте, неразумно при каждом изменении стартовать доп.поток "с нуля". Старт системой доп.потока связан с занятием ресурсов, и всякий раз при старте это требует времени и, порой, - немалого. Это все равно что ощутимая разница между стартом горячего и холодного двигателей : машина гораздо быстрей выдаст нужную полезную мощность, если она "теплая".

Тебе, очевидно, следует перед началом сеанса редактирования текста в Memo однократно стартовать доп.поток (тело которого будет заниматься парсингом и интерпретацией), а перед завершением сеанса - уничтожить его. В процессе же сеанса всякий раз при любом изменении текста в контексте обработки события Memo.OnChange() ты шлешь сообщение доп.потоку, информируя его о подробностях произошедших изменений (PostThreadMessage, например). До момента получения любых сообщений стартовавший доп.поток находится в состоянии циклического их ожидания. В состоянии ожидания доп.поток не занимает квант-ресурсы процесса и системы в целом, т.о. не "тормозя" другие потоки и процессы.

Получив сообщение (например, как результат вызова GetMessage), поток выходит из состояния ожидания, проверяет флаг Terminated (на предмет, не должен ли он был "закруглиться", пока "спал") и, проанализировав параметры сообщения, начинает действовать собственно "по хозяйству". Отработав же сообщение - снова "засыпает" в ожидании очер.сообщения.


kull   (2002-06-21 13:13:00) [18]

1. Можно просто FreeOnTerminate := True вместо Free
2. А зачем поток снова создается в OnTerminate?


alxx   (2002-06-21 12:47:00) [19]

Зависает после пары минут ввода.


alxx   (2002-06-21 12:45:00) [20]

Вот. Сами попробуйте. Или укажите на ошибку:


unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, RxRichEd, ExtCtrls, Buttons, UThread;


type
TForm1 = class(TForm)
RE: TRxRichEdit;
Label1: TLabel;
procedure REChange(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure OnFPTerminate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
Running :Boolean;
NeedToRun:Boolean;
Expr :String;
FT :TMyThread;
end;

var
Form1: TForm1;

implementation


{$R *.dfm}

procedure TForm1.OnFPTerminate(Sender: TObject);
Begin
FT.Free;
FT:=nil;
If needToRun then
Begin
FT:=TMyThread.Create(True);
FT.OnTerminate:=OnFPTerminate;
FT.Lab:=Label1;
FT.Priority:= tpLower;
FT.Suspended:=False;
NeedToRun:=False;
End;
End;

procedure TForm1.FormCreate(Sender: TObject);
begin
Running:=False;
NeedToRun:=False;
end;

procedure TForm1.REChange(Sender: TObject);
var hThread:THandle;
ThreadID:DWord;
Expr1:String;
i:Integer;
begin

Expr1:=""; For i:=0 to RE.Lines.Count-1 do Expr1:=Expr1+RE.Lines.Strings[i];
If Expr1<>Expr Then
Begin
Expr:=Expr1;
Begin

if FT<>nil Then
Begin
NeedToRun:=True;
FT.Terminate;
End
Else
Begin
FT:=TMyThread.Create(True);
FT.OnTerminate:=OnFPTerminate;
FT.Lab:=Label1;
FT.Priority:= tpLower;
FT.Suspended:=False;
End;

Running:=True; {}
End;
End;
{}
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
If FT<>nil Then
Begin
FT.Free;
End;
end;

end.


unit UThread;

interface

uses
Classes, StdCtrls, SysUtils, Messages, Windows;

Const WM_ProcessDONE = wm_User+0;

type
TMyThread = class(TThread)
private
Val:Integer;
procedure UpdateCaption;
protected
procedure Execute; override;
public
Lab:TLabel;
Han:THandle;
end;

implementation

procedure TMyThread.UpdateCaption;
Begin
Lab.Caption:=IntToStr(Val);
Lab.Repaint;
End;

procedure TMyThread.Execute;
Var i:Integer;
begin
For i:=1 to 1000 do
Begin
If Terminated Then Break;
Val:=i;
Synchronize(UpdateCaption);
End;

{ Place thread code here }
end;

end.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо