Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2013.07.14;
Скачать: CL | DM;

Вниз

WaitForSingleObject   Найти похожие ветки 

 
ford ©   (2012-11-21 10:33) [0]

Добрый день!
Написал небольшую процедуру, для обработки регулярными выражениями (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?


 
DVM ©   (2012-11-21 10:39) [1]


> Попытался исправлять ошибки в данных из-за которых происходит
> зависание, но всего предусмотреть не получается.
> Решил вывести процедуру обработки в отдельный поток и завершать
> его принудительно если он работает более минуты.

Если поток подвиснет на execute как завершать то его будешь? В чем заключается подвисание? В цикл бесконечный что ли где попадаешь? Цкл твой или внутри TRegExpr?


 
ford ©   (2012-11-21 10:42) [2]


> В чем заключается подвисание?

TRegExpr уходит в бесконечный цикл.


 
ford ©   (2012-11-21 11:12) [3]

Нашел в чем ошибка
между

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;


 
sniknik ©   (2012-11-21 11:46) [4]

> между
> h.Execute;
Execute; вообще не нужно выполнять... тем более вызовом в основном потоке. в созданном он начнет выполняться "сам"... если не создавать с приостановкой как ты конечно.


 
Медвежонок Пятачок ©   (2012-11-21 11:48) [5]

h:=TThrSearch.create(expr,st.Text);
h.Execute;


Что за ересь?
нафига такой вторичный поток, если он выполняется в основном?


 
Медвежонок Пятачок ©   (2012-11-21 11:49) [6]

2. И зачем такой поток, если основной тупо его ждет через  WaititForSingleObject?


 
ford ©   (2012-11-21 12:02) [7]


> 2. И зачем такой поток, если основной тупо его ждет через
>  WaititForSingleObject?

Я же написал в вопросе, т.к. зависает процедура иногда (редко но зависает), чтобы не зависала вся программа, я вынес её в поток и по таймауту отрубаю поток если он "завис"


 
sniknik ©   (2012-11-21 12:05) [8]

> я вынес её в поток
нет, у тебя нет потока, у тебя объект потока, но выполняются ВСЕ действия основном... что написал то и получил.


 
ford ©   (2012-11-21 12:07) [9]

пришлось немного переделать, и все вроде заработало как надо, т.е. при "зависании" закрывает поток и "сообщает" об этом.

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;


Сделано не "красиво", но вроде работает.  Буду очень благодарен, если подскажете как сделать лучше :)


 
ford ©   (2012-11-21 12:09) [10]


> нет, у тебя нет потока, у тебя объект потока

А по подробнее можно? Что значит "нет потока"?
разве создавая объект потомка Tthread я не создаю поток отдельно работающий от основного потока?


 
sniknik ©   (2012-11-21 12:16) [11]

> Что значит "нет потока"?
это относилось к вызову а ля [0] на что и был комментарий.

> разве создавая объект потомка Tthread я не создаю поток отдельно работающий от основного потока?
ты создаешь объект, и вот этот объект создает поток, но только при правильном использовании. заблокировать создание и вызвать код в основном это не правильное...
написать код мало, нужна еще и логика программирования...


 
DVM ©   (2012-11-21 12:20) [12]


> Буду очень благодарен, если подскажете как сделать лучше
> :)

Искать корни проблемы надо а не маскировать ее. Т.е надо выяснять почему в цикл бесконечный попадаешь.


 
DVM ©   (2012-11-21 12:21) [13]


> Буду очень благодарен, если подскажете как сделать лучше

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


 
sniknik ©   (2012-11-21 12:25) [14]

> Буду очень благодарен, если подскажете как сделать лучше :)
напиши внятные комментарии чего хочешь добиться, смысл, вызовов каждой команды...
вот зачем цикл с Terminated если проход "разовый" (Terminate;)? одно взаимоисключает другое.
зачем вообще поток если жесткая завязка с ожиданием окончания в основном? ты либо линейно пишешь, либо с потоками.
подождать 10 сек? у тебя какие обьемы текста чтобы такие задержки были?... если текст большей его что обрабатывать не нужно?


 
Медвежонок Пятачок ©   (2012-11-21 12:45) [15]

Буду очень благодарен, если подскажете как сделать лучше :)


Выдели код метода Execute, сделай Ctrl+X
перейди в модуль основного потока, сделай Ctl+V
Удали модуль потока вообще.
Будет все абсолютно тоже самое, но будет меньше проблем и ошибок.


 
ford ©   (2012-11-21 12:47) [16]


> подождать 10 сек? у тебя какие обьемы текста чтобы такие
> задержки были?... если текст большей его что обрабатывать
> не нужно?

объемы текста не большие, но количество доходит до нескольких тысяч. При нормальном выполнении процедура с поиском регулярных выражений по тексту работает оч. быстро. Но попадаются тексты которые содержат "ошибку" которая приводит к бесконечному циклу при выполнении FindNext у TRegExpr (например последнее "зависание" было при обработке 18000 текстов, из которых всего один был "ошибочный")
я попытался найти в исходниках TRegExpr этот момент и его откорректировать, но к сожалению без результатно, т.к. необходимо разобраться во всей логике работы этой библиотеки. Поэтому решил попробовать обойти проблему таким образом. А именно, запустить поиск в отдельном потоке и ждать завершения его выполнения и если он не выполниться за определенной время, то считать что он "завис" и сбросить его, а заодно и обработку такого текста. "Ощибочный" текст выдать пользователю, на "исправление" и продолжить разбор остальных текстов.


 
ford ©   (2012-11-21 12:51) [17]


> Выдели код метода Execute, сделай Ctrl+X
> перейди в модуль основного потока, сделай Ctl+V
> Удали модуль потока вообще.
> Будет все абсолютно тоже самое, но будет меньше проблем
> и ошибок.

"хахашечкой пахнуло" © "Уральские пельмени"


 
Медвежонок Пятачок ©   (2012-11-21 12:51) [18]

гениально.
Был один поток, который искал.
Стало два потока. Один ищет, другой вообще ничего не делает, а только ждет.

Вопрос: зачем ему ждать, если он :
1. в это время сам может искать
2. в это время он нихрена вообще не делает, в том числе не обрабатывает сообщения и интерфейс gui не обновляется

Ответ:
А бес понятия, мне просто вторичные потоки нравятся.


 
sniknik ©   (2012-11-21 13:03) [19]

> Поэтому решил попробовать обойти проблему таким образом.
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
--------------------------------------------------------------}


это не у них, это у тебя, проблема. а "обходишь" у них.


 
sniknik ©   (2012-11-21 13:06) [20]

> prevent infinite looping if empty string match r.e.
предотвратить бесконечное перекручивание если пустая строка подходит всему...
ну типа того.


 
sniknik ©   (2012-11-21 13:10) [21]

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


 
ford ©   (2012-11-21 13:14) [22]


> sniknik ©   (21.11.12 13:03) [19]
> это не у них, это у тебя, проблема. а "обходишь" у них.


Разбирать чужие исходники это всегда сложнее и дольше. Тем более, что "ошибка", например в тестовом примере возникает 1 на 18000, и как по Вашему, стоит лезть в исходники TRegExpr или может проще и быстрее сделать как я? А именно запустить в потоке и по срабатыванию таймаута отдать текст обратно юзеру, и продолжить обработку остальных 17999 "нормальных" текстов.
Мало того, но сделав именно так, я получил еще и кусок работающего кода, который можно использовать в других "зависающих" ситуациях.


 
ford ©   (2012-11-21 13:17) [23]


> это же у тебя подсчет количества вхождений фразы в текст?

не одной и не просто фразы, а целого множества "конструкций".
Для поиска фразы как последовательности символов я бы не заморачивался с регулярными выражениями.


 
ford ©   (2012-11-21 13:20) [24]


> Медвежонок Пятачок ©   (21.11.12 12:51) [18]
>
> гениально.
> Был один поток, который искал.
> Стало два потока. Один ищет, другой вообще ничего не делает,
>  а только ждет.
>
> Вопрос: зачем ему ждать, если он :
> 1. в это время сам может искать
> 2. в это время он нихрена вообще не делает, в том числе
> не обрабатывает сообщения и интерфейс gui не обновляется
>
> Ответ:
> А бес понятия, мне просто вторичные потоки нравятся.


Ответ:
См. пункт 0.


 
sniknik ©   (2012-11-21 13:32) [25]

> стоит лезть в исходники TRegExpr или может проще и быстрее сделать как я?
я вообще сомневаюсь, что ошибка в TRegExpr. она скорее у тебя, в "той" обработке. и ты ее возможно даже исправишь переписав по новому, а возможно наплодишь еще глюков (уже в общем то, работает исключительно на взаимоисключениях)...  как будет проще и быстрее еще вопрос.


 
DVM ©   (2012-11-21 13:36) [26]


> ford ©   (21.11.12 13:14) [22]
>

А что ты в тексте ищешь то? Уже неоднократно натыкался на случаи, когда без регулярок поиск ускорялся буквально в 100 раз.


 
Медвежонок Пятачок ©   (2012-11-21 14:05) [27]

Ставлю два байта на то, что бесконечный цикл написан не сорокиным (автором либы) а тобой.
И бесконечный он потому, что ты либо не умеешь писать регулярки, либо просто не умеешь анализировать что ты передаешь методам TRegExpr.

И вместо того, чтобы научиться программировать или хотя бы поставить в свой бесконечный цикл ограничение на макс. количество итераций или на время выполнения ты нагородил вторичный поток, вся польза от которого - возможность бросить поток, в котором начался твой бесконечный цикл. Причем именно бросить, а не остановить со всеми вытекающими и утекающими последствиями.


 
ford ©   (2012-11-21 14:09) [28]


> sniknik ©   (21.11.12 13:32) [25]
>
> > стоит лезть в исходники TRegExpr или может проще и быстрее
> сделать как я?
> я вообще сомневаюсь, что ошибка в TRegExpr. она скорее у
> тебя, в "той" обработке...

обработка :

r:=TRegExpr.Create;
     r.Expression:=fexpr;
     if r.Exec(fData) Then
      Begin
       repeat
        inc(k);
       until not r.ExecNext;
      End;


fExpr - строка с регулярным выражением
fdata - текст, размером от 1 до 100килобайт.
и fExpr и fData не пусты
для 17999 текстов все ОК, для одного, на тех же самых регулярных выражениях, r.ExecNext уходит в бесконечный цикл.

спрашивается

> ты ее возможно даже исправишь переписав по новому

Как вы себе это представляете? переписать библиотеку RegExpr? :)


 
Медвежонок Пятачок ©   (2012-11-21 14:13) [29]

что и требовалось доказать


 
Медвежонок Пятачок ©   (2012-11-21 14:17) [30]

r.ExecNext уходит в бесконечный цикл.

Кто тебе это сказал?
Уверен, что это не твой repaet уходит в бесконечность?


 
ford ©   (2012-11-21 14:18) [31]


> Медвежонок Пятачок ©   (21.11.12 14:13) [29]
>
> что и требовалось доказать

Ну главное что ваше трольное себялюбие не затронуто.


 
ford ©   (2012-11-21 14:19) [32]


> Медвежонок Пятачок ©   (21.11.12 14:17) [30]
>
> r.ExecNext уходит в бесконечный цикл.
>
> Кто тебе это сказал?
> Уверен, что это не твой repaet уходит в бесконечность?

Вы вообще видели Дельфи?


 
Медвежонок Пятачок ©   (2012-11-21 14:22) [33]

Ты лучше поищи какую-либо цикличность внутри

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


фонарик только не забудь


 
ford ©   (2012-11-21 14:29) [34]


> Медвежонок Пятачок ©   (21.11.12 14:22) [33]
>
> Ты лучше поищи какую-либо цикличность внутри

Ну Вы блин даете. Сами фонарик-то не забудьте :)

....
Result := ExecPrim (Offset);
end; { of function TRegExpr.ExecNext



 
Медвежонок Пятачок ©   (2012-11-21 14:31) [35]

И чего?

Внутри ExecPrim есть цикл, который может быть бесконечным?

for i := 0 to NSUBEXP - 1 do begin


 
Медвежонок Пятачок ©   (2012-11-21 14:36) [36]

даже если он там есть,

то есть TRegExpr.Exec (AOffset: integer)

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


 
ford ©   (2012-11-21 16:02) [37]


> Медвежонок Пятачок ©   (21.11.12 14:36) [36]


> чтобы тупо сосчитать все матчи внутри искомого твой цикл
> с inc() вообще не нужен.

Вы хотите чтобы я весь код привел в студию? :) Не говорите глупостей :)

при поиске места "зависания", я закоментил все что есть в цикле, и оттрасировал этот ExecNext. Нашел там этот "цикл" который состоял из нескольких вызовов. Но разбираться дальше с этой библиотекой - куча потраченного в пустую времени.

Но то что "зацикливание" происходит в недрах библиотеки RegExpr - факт. Может я не совсем корректно написал регулярное выражение, но опять же факт остается фактом, программа работает, и на данный момент ПРАВИЛЬНО обработала несколько десятков тысяч текстов, сохранив в отдельную папочку, всего пару файликов с текстами которые вызвали "зависание". Исправить которые и подсунуть ей их еще раз не составит труда.

Как говориться "Show must go on"


 
DVM ©   (2012-11-21 16:09) [38]


>  программа работает, и на данный момент ПРАВИЛЬНО обработала
> несколько десятков тысяч текстов, сохранив в отдельную папочку,
>  всего пару файликов с текстами которые вызвали "зависание".
>  Исправить которые и подсунуть ей их еще раз не составит
> труда.

т.е на чистом проекте данные файлы вызывают проблемы у TregExpr? И проблема стабильно воспроизводится? Тогда может регулярное выражение выложишь на пару с проблемным файлом.


 
Медвежонок Пятачок ©   (2012-11-21 16:19) [39]

Но то что "зацикливание" происходит в недрах библиотеки RegExpr - факт.

Факт факт.
Конечно конечно.
Внутри внутри.

repeat
inc(k);
until not r.ExecNext;


 
anatoly pogoretsky   (2012-11-21 16:19) [40]

> ford  (21.11.2012 16:02:37)  [37]

Ты уже не первый раз грубо
наезжаешь.


 
sniknik ©   (2012-11-21 18:08) [41]

перепиши в стиле
   // find next match:
   //    ExecNext;
   // works same as
   //    if MatchLen [0] = 0 then ExecPos (MatchPos [0] + 1)
   //     else ExecPos (MatchPos [0] + MatchLen [0]);

   // but it"s more simpler !
   // Raises exception if used without preceeding SUCCESSFUL call to
   // Exec* (Exec, ExecPos, ExecNext). So You always must use something like
   // if Exec (InputString) then repeat { proceed results} until not ExecNext;

для проблемного файла регулярки. проверь.

а лучше действительно -
DVM ©   (21.11.12 16:09) [38]
> Тогда может регулярное выражение выложишь на пару с проблемным файлом.



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

Текущий архив: 2013.07.14;
Скачать: CL | DM;

Наверх




Память: 0.61 MB
Время: 0.01 c
2-1353266673
Tcount
2012-11-18 23:24
2013.07.14
Как распечатать файлы RTF


15-1362055175
O'ShinW
2013-02-28 16:39
2013.07.14
Как кодировку определить?


15-1361949116
TUser.Click
2013-02-27 11:11
2013.07.14
Qt vs Delphi (мнения профи)


15-1361608048
oldman
2013-02-23 12:27
2013.07.14
Кстати, с праздником, мужики!


8-1231354672
SuperPROgrammist
2009-01-07 21:57
2013.07.14
Быстрый доступ к пикселям растра.