![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
WaitForSingleObject
ford © (2012-11-21 10:33:00)Добрый день!
Написал небольшую процедуру, для обработки регулярными выражениями (TRegExpr) большого массива данных, переданного пользователями. Из-за некорректных данных, процедура иногда повисает. Попытался исправлять ошибки в данных из-за которых происходит зависание, но всего предусмотреть не получается.
Решил вывести процедуру обработки в отдельный поток и завершать его принудительно если он работает более минуты. Наискавшись в интернет, сделал такой от класс:
type TThrSearch=class(TThread)
private
fData:String;
fExpr:String;
public
constructor create(expr,Data:String);
destructor destroy; override;
procedure Execute; override;
end;
Constructor TThrSearch.create;
begin
inherited Create(True);
fData:=data;
fExpr:=expr;
End;
destructor TThrSearch.destroy;
Begin
inherited;
End;
procedure TThrSearch.Execute;
Var r:TRegExpr;
k:Integer;
Begin
try
ReturnValue:=-1;
k:=0;
r:=TRegExpr.Create;
r.Expression:=fexpr;
if r.Exec(fData) Then
Begin
repeat
inc(k);
until not r.ExecNext;
End;
finally
r.Free;
ReturnValue:=k;
end;
End;
далее в программе создаю объект этого класса и выполняю метод Execute;
try
k:=0;
h:=TThrSearch.create(expr,st.Text);
h.Execute;
res:=WaitForSingleObject(h.Handle,2000);
if h.ReturnValue=-1 Then h.Terminate
Else k:=h.ReturnValue;
finally
h.Free;
result:=k;
end;
На сколько я понял
процедура WaitForSingleObject, должна останавливать основной поток программы и ждать сигнала от потока о завершении и если не дождалась то по таймауту передать управление основному потоку. Но
в при выполнении строки
res:=WaitForSingleObject(h.Handle,2000);
программа не зависимо от того завершился поток или нет, ждет указанный 2000 миллисекунд.
Подскажите, где ошибка, почему WaitForSingleObject, всегда ждет установленное таймаутом время и не реагирует на завершение процедуры execute?
sniknik (2012-11-21 13:10:00) [21]вообще на регулярках прямо помешались все... чуть подумать и можно сделать по другому, проще, быстрее... это же у тебя подсчет количества вхождений фразы в текст?
sniknik (2012-11-21 13:06:00) [22]> prevent infinite looping if empty string match r.e.
предотвратить бесконечное перекручивание если пустая строка подходит всему...
ну типа того.
sniknik (2012-11-21 13:03:00) [23]> Поэтому решил попробовать обойти проблему таким образом.
DVM © (21.11.12 12:20) [12]
> Искать корни проблемы надо а не маскировать ее. Т.е надо выяснять почему в цикл бесконечный попадаешь.
function TRegExpr.ExecNext : boolean;
var offset : integer;
begin
Result := false;
if not Assigned (startp[0]) or not Assigned (endp[0]) then begin
Error (reeExecNextWithoutExec);
EXIT;
end;
// Offset := MatchPos [0] + MatchLen [0];
// if MatchLen [0] = 0
Offset := endp [0] - fInputString + 1; //###0.929
if endp [0] = startp [0] //###0.929
then inc (Offset); // prevent infinite looping if empty string match r.e.
Result := ExecPrim (Offset);
end; { of function TRegExpr.ExecNext
--------------------------------------------------------------}
это не у них, это у тебя, проблема. а "обходишь" у них.
Медвежонок Пятачок (2012-11-21 12:51:00) [24]гениально.
Был один поток, который искал.
Стало два потока. Один ищет, другой вообще ничего не делает, а только ждет.
Вопрос: зачем ему ждать, если он :
1. в это время сам может искать
2. в это время он нихрена вообще не делает, в том числе не обрабатывает сообщения и интерфейс gui не обновляется
Ответ:
А бес понятия, мне просто вторичные потоки нравятся.
ford (2012-11-21 12:51:00) [25]
> Выдели код метода Execute, сделай Ctrl+X
> перейди в модуль основного потока, сделай Ctl+V
> Удали модуль потока вообще.
> Будет все абсолютно тоже самое, но будет меньше проблем
> и ошибок.
"хахашечкой пахнуло" © "Уральские пельмени"
ford (2012-11-21 12:47:00) [26]
> подождать 10 сек? у тебя какие обьемы текста чтобы такие
> задержки были?... если текст большей его что обрабатывать
> не нужно?
объемы текста не большие, но количество доходит до нескольких тысяч. При нормальном выполнении процедура с поиском регулярных выражений по тексту работает оч. быстро. Но попадаются тексты которые содержат "ошибку" которая приводит к бесконечному циклу при выполнении FindNext у TRegExpr (например последнее "зависание" было при обработке 18000 текстов, из которых всего один был "ошибочный")
я попытался найти в исходниках TRegExpr этот момент и его откорректировать, но к сожалению без результатно, т.к. необходимо разобраться во всей логике работы этой библиотеки. Поэтому решил попробовать обойти проблему таким образом. А именно, запустить поиск в отдельном потоке и ждать завершения его выполнения и если он не выполниться за определенной время, то считать что он "завис" и сбросить его, а заодно и обработку такого текста. "Ощибочный" текст выдать пользователю, на "исправление" и продолжить разбор остальных текстов.
Медвежонок Пятачок (2012-11-21 12:45:00) [27]Буду очень благодарен, если подскажете как сделать лучше :)
Выдели код метода Execute, сделай Ctrl+X
перейди в модуль основного потока, сделай Ctl+V
Удали модуль потока вообще.
Будет все абсолютно тоже самое, но будет меньше проблем и ошибок.
sniknik (2012-11-21 12:25:00) [28]> Буду очень благодарен, если подскажете как сделать лучше :)
напиши внятные комментарии чего хочешь добиться, смысл, вызовов каждой команды...
вот зачем цикл с Terminated если проход "разовый" (Terminate;)? одно взаимоисключает другое.
зачем вообще поток если жесткая завязка с ожиданием окончания в основном? ты либо линейно пишешь, либо с потоками.
подождать 10 сек? у тебя какие обьемы текста чтобы такие задержки были?... если текст большей его что обрабатывать не нужно?
DVM (2012-11-21 12:21:00) [29]
> Буду очень благодарен, если подскажете как сделать лучше
А еще проще в цикл вставить счетчик итераций и когда их больше максимально возможного прерывать его и не понадобится вся эта кухня с WaitFor
DVM (2012-11-21 12:20:00) [30]
> Буду очень благодарен, если подскажете как сделать лучше
> :)
Искать корни проблемы надо а не маскировать ее. Т.е надо выяснять почему в цикл бесконечный попадаешь.
sniknik (2012-11-21 12:16:00) [31]> Что значит "нет потока"?
это относилось к вызову а ля [0] на что и был комментарий.
> разве создавая объект потомка Tthread я не создаю поток отдельно работающий от основного потока?
ты создаешь объект, и вот этот объект создает поток, но только при правильном использовании. заблокировать создание и вызвать код в основном это не правильное...
написать код мало, нужна еще и логика программирования...
ford (2012-11-21 12:09:00) [32]
> нет, у тебя нет потока, у тебя объект потока
А по подробнее можно? Что значит "нет потока"?
разве создавая объект потомка Tthread я не создаю поток отдельно работающий от основного потока?
ford (2012-11-21 12:07:00) [33]пришлось немного переделать, и все вроде заработало как надо, т.е. при "зависании" закрывает поток и "сообщает" об этом.
type TThrSearch=class(TThread)
private
fData:String;
fExpr:String;
public
constructor create(expr,Data:String);
destructor destroy; override;
procedure Execute; override;
procedure DoWork;
end;
Constructor TThrSearch.create;
begin
fData:=data;
fExpr:=expr;
inherited Create(True);
Resume;
End;
destructor TThrSearch.destroy;
Begin
inherited;
End;
procedure TThrSearch.Execute;
begin
While not Terminated do DoWork;
End;
procedure TThrSearch.DoWork;
Var r:TRegExpr;
k:Integer;
Begin
try
ReturnValue:=-1;
k:=0;
r:=TRegExpr.Create;
r.Expression:=fexpr;
if r.Exec(fData) Then
Begin
repeat
inc(k);
until not r.ExecNext;
End;
finally
r.Free;
ReturnValue:=k;
end;
Terminate;
end;
и в основном потоке
try
k:=0;
h:=TThrSearch.create(expr,st.Text);
if not h.Terminated Then
begin
res:=WaitForSingleObject(h.Handle,10000);
if res<>WAIT_OBJECT_0 Then Err:=1;
end;
if h.ReturnValue=-1 Then h.Terminate
Else k:=h.ReturnValue;
finally
h.Free;
result:=k;
end;
Сделано не "красиво", но вроде работает. Буду очень благодарен, если подскажете как сделать лучше :)
sniknik (2012-11-21 12:05:00) [34]> я вынес её в поток
нет, у тебя нет потока, у тебя объект потока, но выполняются ВСЕ действия основном... что написал то и получил.
ford (2012-11-21 12:02:00) [35]
> 2. И зачем такой поток, если основной тупо его ждет через
> WaititForSingleObject?
Я же написал в вопросе, т.к. зависает процедура иногда (редко но зависает), чтобы не зависала вся программа, я вынес её в поток и по таймауту отрубаю поток если он "завис"
Медвежонок Пятачок (2012-11-21 11:49:00) [36]2. И зачем такой поток, если основной тупо его ждет через WaititForSingleObject?
Медвежонок Пятачок (2012-11-21 11:48:00) [37]h:=TThrSearch.create(expr,st.Text);
h. Execute;
Что за ересь?
нафига такой вторичный поток, если он выполняется в основном?
sniknik (2012-11-21 11:46:00) [38]> между
> h.Execute;
Execute; вообще не нужно выполнять... тем более вызовом в основном потоке. в созданном он начнет выполняться "сам"... если не создавать с приостановкой как ты конечно.
ford (2012-11-21 11:12:00) [39]Нашел в чем ошибка
между
h.Execute;
и
res:=WaitForSingleObject(h.Handle,2000);
поток уже успевал выполниться :)
сделал так
if not h.Terminated Then
begin
res:=WaitForSingleObject(h.Handle,10000);
if res<>WAIT_OBJECT_0 Then Err:=1;
end;
ford (2012-11-21 10:42:00) [40]
> В чем заключается подвисание?
TRegExpr уходит в бесконечный цикл.