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

Вниз

Зачем-то глючат нити... Хотя не должны...   Найти похожие ветки 

 
alxx   (2002-06-21 10:25) [0]

У меня на форме лежит 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;


 
alxx   (2002-06-21 10:29) [1]

Там только в Memo1Change - не RE.Lines надо, а Memo1.Lines - это я по частям выдергивал - перепутал с RichEdit"oм


 
Digitman   (2002-06-21 10:37) [2]

1. TextOut() - не thread-safe ф-ция.
2. У тебя напрочь отсутствует синхронизация между потоками


 
kull   (2002-06-21 10:38) [3]

А почему не использовать класс TThread.


 
alxx   (2002-06-21 10:40) [4]

Синхронизации конечно нет, но я TextOut убираю и все равно проблемы остаются...
А вот с какими потоками я должен синхронизировать - у меня же он один (мой). Как же быть то?


 
alxx   (2002-06-21 10:41) [5]

Класс TThread тоже не помогает...


 
kull   (2002-06-21 10:50) [6]

Почему же, помогает.
Делает работу более удобной.

Избавляет от ненужной рутины типа возни с Handle - ми, вызовов API - шных функций и т.п. для того он и сделан.

А если нет синхронизации, то и TThread не поможет.


 
Digitman   (2002-06-21 11:28) [7]

>alxx

А каков вообще смысл всего этого ?


 
Dapo   (2002-06-21 12:18) [8]

С потоками с помощью API не работал. Это и не к чему, по крайней мере в решении твоей проблемы. Используй TThread. Люди правильно говорят. Если у тебя поток только считает, и не использует VCL то его и синхронизировать не надо.
unit Unit2;

interface

uses
Classes;

type
MyThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;

implementation

{ MyThread }

procedure MyThread.Execute;
var i:integer;
j:real;
begin
While not Terminated do
begin
{ Пиши сюда свои вычисления }
j:=i+10 ;
If j>10000 then Terminate;
end;
end;

end.
В Memo1.OnChange:

var Mythread:TMyThread;
....
//Проверь запущен или нет, если нет
MyThread:=TMyThread.Create(false);
....
end;


 
alxx   (2002-06-21 12:33) [9]

> Digitman
Ну у меня обработка строк происходит при изменении. Что-то типа интерпретатора. Но даже просто посчитать до 10000 не получается.

> Dapo
Переделал я под TThread, но зависает она все равно периодически.
Блин...


 
alxx   (2002-06-21 12:35) [10]

Может, кто-нибудь может показать примерчик, заведомо работающий?
Что-то я совсем уже запарился...


 
kull   (2002-06-21 12:37) [11]

А ты делаешь FreeOnTerminate = True ?


 
kull   (2002-06-21 12:40) [12]

И я так понимаю что при каждом OnChange надо старый поток уничтожать, а новый запускать, чтобы несколько потоков не интерпретировали одновременно.


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

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


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.


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

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


 
kull   (2002-06-21 13:13) [15]

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


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

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

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

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


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


> Digitman © (21.06.02 13:45)


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


 
Digitman   (2002-06-21 14:14) [18]

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


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

> Digitman

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

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



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


> Digitman © (21.06.02 14:14)


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


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


> Digitman © (21.06.02 14:14)

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


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

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


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

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

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


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

>kull

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


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

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


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

О-О-О!....

О-О-О!....

Я балдею...

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

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

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


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

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

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


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

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


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

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


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


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


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

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


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

>kull

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

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


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

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



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

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

Наверх




Память: 0.54 MB
Время: 0.005 c
14-9978
Katja
2002-06-02 08:57
2002.07.04
Hook


3-9756
EAlexander
2002-06-10 13:55
2002.07.04
Как сохранить произвольный DataSet в файл DBF


6-9958
КСА
2002-04-23 05:46
2002.07.04
Очень интересная задачка


14-10009
andron
2002-05-30 13:14
2002.07.04
Интересное наблюдение


6-9945
ec
2002-04-22 12:51
2002.07.04
ICQ+SMS





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский