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

Вниз

Вопрос по потокам.   Найти похожие ветки 

 
dabreezy   (2006-02-07 18:57) [0]

Добрый вечер.
У меня такой вопрос по потокам (целый день башку ломаю)
есть процедура запуска потока (в ней цикл с сложными вычислениями):

procedure TMyThread1.Execute;
begin
...
 repeat
 until (terminated) or (i1=i-1);

...

 synchronize (Thread_done);

end;

Далее функция Thread_done (thread_running - кол-во потоков):

procedure TMyThread1.Thread_done;
begin
 form1.thread_running:=form1.thread_running-1;
end;

Так вот такая штука получается, когда все потоки завершены, то получается что иногда работает нормально(thread_runnig=0), а иногда thread_running=1 или 2. Причем чем больше потоков, тем чаще такое бывает! При 3х-6 потоков такое практически не бывает.
Объясните пожалуйста в чем дело.


 
Zeqfreed ©   (2006-02-07 19:08) [1]

У класса TThread есть специальное событие OnTerminate, возникающее после отработки метода Execute. А вообще, в приведенном коде, вроде нет ошибок.


 
Defunct ©   (2006-02-07 19:11) [2]

оповещайте форму о завершении из потока с помощью PostMessage. В обработчике сообщения уменьшайте переменную thread_runnung.


 
dabreezy   (2006-02-07 19:17) [3]


> Zeqfreed ©   (07.02.06 19:08) [1]
> У класса TThread есть специальное событие OnTerminate,

И так пробовал не работает :(


 
dabreezy   (2006-02-07 19:19) [4]


> Defunct ©   (07.02.06 19:11) [2]
> оповещайте форму о завершении из потока с помощью PostMessage.
>  В обработчике сообщения уменьшайте переменную thread_runnung.
>

А как это сделать?


 
Zeqfreed ©   (2006-02-07 19:22) [5]

[2] Defunct ©   (07.02.06 19:11)
А чем это лучше обычного вызова метода формы в контексте основного потока?

dabreezy   (07.02.06 18:57)
Все-таки мне кажется, что ошибка где-то в другом месте. Не в том коде, что Вы привели.


 
dabreezy   (2006-02-07 19:34) [6]


> Zeqfreed ©   (07.02.06 19:22) [5]

Так в том то и все дело, что synchronize (Thread_done); выполняется прямо перед концом функции. Должно вроде нормально работать, оно иногда и работает. Причем даже пробовал следующее: делал переменную у каждого потока flag. В начале функции flag=0, а в конце flag=1, все равно не помогает


 
Leonid Troyanovsky ©   (2006-02-07 19:40) [7]


> dabreezy   (07.02.06 19:34) [6]

> Так в том то и все дело, что synchronize (Thread_done);
> выполняется прямо перед концом функции. Должно вроде нормально
> работать, оно иногда и работает. Причем даже пробовал следующее:


Нормально должно работать в OnTerminate, при условии, конечно,
что thread_runnung инкрементируется правильно.

--
Regards, LVT.


 
Defunct ©   (2006-02-07 19:42) [8]

Zeqfreed ©   (07.02.06 19:22) [5]
Хотя бы тем что не потребуется использовать Synchronize

dabreezy   (07.02.06 19:19) [4]
> А как это сделать?

например так:

в модуле описанием потока:
const WM_THREADDONE = WM_USER + 1;

type
  TMyThread = class(TThead)
  ...
  protected
     FOwnerWnd : HWND;
     procedure Execute;
  public
     constructor Create( AOwnerWND: HWND);
  end;

constructor TMyThread.Create;
begin
  inherited Create( true );
  FOwnerWND := AOwnerWND;
  ...
  resume;
end;

procedure TMyThread.Execute;
begin
  ...
  PostMessage( FOwnerWND, WM_THREADDONE, 0, 0);
end;


в модуле с формой:
 TForm1 = class(TForm)
 ...
    procedure ThreadDoneHandler( var Msg: TMessage);message WM_THREADDONE;
    procedure StartThread;
 end;

procedure TForm1.ThreadDoneHandler;
begin
  dec( Thread_running )
end;

procedure StartThread;
begin
  try
     TMyThread.Create( Handle );
     inc( Thread_running );
  except
     ShowMessage(" could not start new thread" )
  end;
end;


 
dabreezy   (2006-02-07 19:45) [9]


>
> Нормально должно работать в OnTerminate, при условии, конечно,
>  
> что thread_runnung инкрементируется правильно.

Я запускаю потоки вот так:
   Thread_array: array [1..50] of TMyThread1;

...
    thread_kol:=25;
    thread_running:=thread_kol;
    for i:=1 to Thread_kol do
     begin
      Thread_array[i]:=TMyThread1.Create(false);
      Thread_array[i].str:=inttostr(i);
     end;

Соответственно точно известно что потоков запущено 25. Вот от thread_running и отнимается по единице когда какой-нибуть поток остановлен.


 
Leonid Troyanovsky ©   (2006-02-07 19:48) [10]


> Leonid Troyanovsky ©   (07.02.06 19:40) [7]

> Нормально должно работать в OnTerminate, при условии, конечно,
> что thread_runnung инкрементируется правильно.


И при условии, что потокам не делают TerminateThread.

--
Regards, LVT.


 
dabreezy   (2006-02-07 19:50) [11]


> Leonid Troyanovsky ©   (07.02.06 19:48) [10]
>
> > Leonid Troyanovsky ©   (07.02.06 19:40) [7]
>
> > Нормально должно работать в OnTerminate, при условии,
> конечно,
> > что thread_runnung инкрементируется правильно.
>
>
> И при условии, что потокам не делают TerminateThre

А кто это может делать? Windows? В программе ничего такого не делается.


 
dabreezy   (2006-02-07 19:51) [12]


> Defunct ©   (07.02.06 19:42) [8]
> Zeqfreed ©   (07.02.06 19:22) [5]
> Хотя бы тем что не потребуется использовать Synchronize
>
> dabreezy   (07.02.06 19:19) [4]
> > А как это сделать

Спасибо большое. Попробую. Надеюсь получится


 
Leonid Troyanovsky ©   (2006-02-07 19:52) [13]


> dabreezy   (07.02.06 19:45) [9]

> Соответственно точно известно что потоков запущено 25.


Точнее было б делать inc(thread_running) в конце цикла.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2006-02-07 19:56) [14]


> dabreezy   (07.02.06 19:50) [11]

> > И при условии, что потокам не делают TerminateThre

> А кто это может делать? Windows? В программе ничего такого
> не делается.


Это может сделать любой, у кого есть хендл потока.
Но, кажется мне, что собака рылась в другом.
Покажи OnTerminate.

--
Regards, LVT.


 
dabreezy   (2006-02-07 20:10) [15]

> Это может сделать любой, у кого есть хендл потока.
> Но, кажется мне, что собака рылась в другом.
> Покажи OnTerminate.

Пробовал делать так:
в объявлении класса формы:

private
   procedure Thread_Done(Sender: TObject);

в цикле
   
   thread_kol:=25;
    for i:=1 to Thread_kol do
    begin
     Thread_array[i]:=TMyThread1.Create(false);
     Thread_array[i].str:=inttostr(i);
     Thread_array[i].OnTerminate:=Thread_done;
     inc(Thread_running);
    end;

procedure TForm1.Thread_done(Sender: TObject);
begin
 Dec(Thread_running);
 if thread_running=0 then
   begin
   ...
   end;
end;


 
begin...end ©   (2006-02-07 20:12) [16]

> Defunct ©   (07.02.06 19:42) [8]
> Хотя бы тем что не потребуется использовать Synchronize

А что плохого в использовании Synchronize?


 
YuRock ©   (2006-02-07 21:39) [17]


> А что плохого в использовании Synchronize?

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

Если не нужна синхронность (а она тут вряд-ли нужна - я телепат :), то лучший вариант - PostMessage.


 
begin...end ©   (2006-02-07 21:46) [18]

> YuRock ©   (07.02.06 21:39) [17]

Я просто не понял, чем Synchronize хуже PostMessage в контексте проблемы автора.


 
YuRock ©   (2006-02-07 22:05) [19]


> Я просто не понял, чем Synchronize хуже PostMessage в контексте
> проблемы автора.


Так более просто, а значит - надежно. И быстрее. А это лучше в любом контексте.


 
Defunct ©   (2006-02-08 01:40) [20]

> А что плохого в использовании Synchronize?

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


 
Defunct ©   (2006-02-08 02:36) [21]

/offtop
2 begin...end

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


 
Leonid Troyanovsky ©   (2006-02-08 08:41) [22]


> dabreezy   (07.02.06 20:10) [15]

> Пробовал делать так:


Так - уже лучше. Хотя, конечно, еще лучше было б
Thread_array[i]:=TMyThread1.Create(True), с завершающим Resume,
бо между Create и назначением OnTerminate может случиться немало
колов времени.

Ну, и, наконец, а как определяется то, что все потоки завершились
(в то время, как thread_running > 0) ?

--
Regards, LVT.


 
dabreezy   (2006-02-08 08:51) [23]


> Leonid Troyanovsky ©   (08.02.06 08:41) [22]
>
> > dabreezy   (07.02.06 20:10) [15]
>
> > Пробовал делать так:
>
>
> Так - уже лучше. Хотя, конечно, еще лучше было б
> Thread_array[i]:=TMyThread1.Create(True), с завершающим
> Resume,
> бо между Create и назначением OnTerminate может случиться
> немало
> колов времени.
>
> Ну, и, наконец, а как определяется то, что все потоки завершились
>
> (в то время, как thread_running > 0) ?


Да, так работает вроде лучше, сейчас тестирую. thread_running проверяется в процедуре обработки onterminate.
Кстати вчера долго тестировал, оказалось, что программа глючила(т.е. оставался один не завершенный поток) из-за того что 1 из 25 потоков, а то и 2 не запускались вообще(проверил это просто, сделал что каждый поток создавал уникальный файл) и вот когда программа глючила как раз файлов было не 25 а 24. Когда работала нормально то файлов было 25. Может это как раз и происходило из-за того что :"Create и назначением OnTerminate может случиться  немало колов времени."?


 
evvcom ©   (2006-02-08 09:10) [24]


> Может это как раз и происходило из-за того что :"Create
> и назначением OnTerminate может случиться  немало колов
> времени."?

Легко. Добавлю к тому, что Inc(thread_running) лучше сделать между Create и Resume.


 
Leonid Troyanovsky ©   (2006-02-08 09:18) [25]


> dabreezy   (08.02.06 08:51) [23]

> Может это как раз и происходило из-за того что :"Create
> и назначением OnTerminate может случиться  немало колов
> времени."?


Если вчерашнее тестирование проводилось с приведенным кодом и
OnTerminate, а 1 из файлов не создавался (т.е., поток не стартовал),
то, видимо, причина не в этом.

Вообще-то, кроме ранее рассмотренного, на наблюдаемую картину
могут повлиять :
- молчаливые исключения типа EAbort в конструкторе потока;
- любые исключения в Execute: поток завершится,  а до Synchronize(..)
 дело не дошло (однако, OnTerminate будет выполнен).

--
Regards, LVT.


 
dabreezy   (2006-02-08 10:44) [26]


> Leonid Troyanovsky ©   (08.02.06 09:18) [25]
>
> > dabreezy   (08.02.06 08:51) [23]
>
> > Может это как раз и происходило из-за того что :"Create
>
> > и назначением OnTerminate может случиться  немало колов
>
> > времени."?
>
>
> Если вчерашнее тестирование проводилось с приведенным кодом
> и
> OnTerminate, а 1 из файлов не создавался (т.е., поток не
> стартовал),
> то, видимо, причина не в этом.
>
> Вообще-то, кроме ранее рассмотренного, на наблюдаемую картину
>
> могут повлиять :
> - молчаливые исключения типа EAbort в конструкторе потока;
>
> - любые исключения в Execute: поток завершится,  а до Synchronize(.
> .)
>  дело не дошло (однако, OnTerminate будет выполнен).
>
> --
> Regards, LVT.

Спасибо за ответы. Сейчас тестирую, даже с 50 потоками работает как часы :)


 
begin...end ©   (2006-02-08 13:20) [27]

> Defunct ©   (08.02.06 02:36) [21]

> Поэтому если хотите вести конструктивный диалог со мной,
> то для начала высказывайте свою точку зрения, а потом задавайте
> вопрос.

Я сам решаю, когда мне высказывать свою точку зрения, и высказывать ли её вообще. Если же в обсуждении какое-то сообщение вызывает у меня вопрос и я хочу его задать, я его задаю (что я и сделал в этой ветке). Отвечать или нет -- разумеется, личное дело того, кому этот вопрос адресуется. И если кто-то за обычным уточняющим вопросом видит желание "подколоть", то это его проблемы.

> В дальнейшем я буду игнорировать все ваши двусмысленные
> ("короткие") сообщения в мой адрес, как потенциально опасные
> для меня.

No comments.



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

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

Наверх





Память: 0.53 MB
Время: 0.047 c
1-1138116612
pasha_golub
2006-01-24 18:30
2006.02.26
Рисование растра в метафайл


2-1139210354
BlackCat
2006-02-06 10:19
2006.02.26
fkCalculated


15-1138870876
Word2003
2006-02-02 12:01
2006.02.26
Полное имя файла внизу страницы во всех создаваемых файлах Word


15-1138719509
Kerk
2006-01-31 17:58
2006.02.26
Кладовка снова в строю.


3-1136373203
кот
2006-01-04 14:13
2006.02.26
Выбор оптимальной базы данных





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