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

Вниз

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]

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



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

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

Наверх





Память: 0.58 MB
Время: 0.003 c
15-1362086783
Androider
2013-03-01 01:26
2013.07.14
Хочу кодить для планшетов


15-1362075484
Pit
2013-02-28 22:18
2013.07.14
Ряд вопросов по ноуту Asus S400c / Win 8


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


15-1361788959
Медвежонок Пятачок
2013-02-25 14:42
2013.07.14
сила воли и свобода выбора у зайца


1-1308586094
Prok186
2011-06-20 20:08
2013.07.14
Как аддрессовать не 2Gb, а 4Gb памяти?





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