Вопрос по потокам TThread

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Вопрос по потокам TThread

Сообщение ronin » 15.02.2010 17:18:10

Вопрос в следующем - при использовании (запуске) потока приложение грузит систему процентов на 30-40, после остановки потока всё ок, нагрузка падает до нуля. Попытался сделать пустое приложение, воткнул конструкции создания и запуска потоков, в общем всё как надо, запустил приложение, по нажатию кнопки при создании потока и последующего его запуска наблюдаю такой эффект.

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

PS варьировать приоритет потока пробовал, не влияет на результат.

ОС: Ubuntu 9.10 (karmic)
Lazarus: 0.9.28.2.0 beta
FPC: 2.2.4

Добавлено спустя 1 минуту 24 секунды:
да .ещё забыл сказать что в потоке никаких действий не выполняется, просто запуск (создание) и потом останов (уничтожение) потока
ronin
постоялец
 
Сообщения: 174
Зарегистрирован: 27.01.2010 00:14:46

Re: Вопрос по потокам TThread

Сообщение hinst » 15.02.2010 22:01:38

а вы поставьте sleep
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Вопрос по потокам TThread

Сообщение ronin » 15.02.2010 22:26:54

почитал материалы в сети, нашёл такой вариант решения, а не подскажете как это работает, а то я немного не догоняю :) что такое sleep понятно, но почему в потоке? и ставить надо в процедуре execute?

Добавлено спустя 45 секунд:
просто в delphi под виндой такого вроде не надо было делать
ronin
постоялец
 
Сообщения: 174
Зарегистрирован: 27.01.2010 00:14:46

Re: Вопрос по потокам TThread

Сообщение eevee » 18.02.2010 10:10:08

примерно так должно быть
Код: Выделить всё
while //поток живет
  // делаем что то в потоке
  sleep(100); // засыпаем на 100 мс
end;
eevee
новенький
 
Сообщения: 63
Зарегистрирован: 29.12.2009 17:52:44
Откуда: Саратов

Re: Вопрос по потокам TThread

Сообщение VirtUX » 18.02.2010 10:28:39

Можно вставить и sleep(1).
Нужно понять, что sleep(1) сообщает ОС о жесткой остановке потока, и тем самым освобождая ресурс ЦП. В Delphi 7 такая же ситуация. Может сейчас они там и добавили автоматически, но - это, помоему, вводит в заблуждение, а не помогает разработчику.
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Вопрос по потокам TThread

Сообщение ronin » 18.02.2010 16:32:35

В Delphi 7 такая же ситуация


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

но - это, помоему, вводит в заблуждение, а не помогает разработчику.


а что здесь такого плохого? я не чувствую какого то дискомфорта под виндой, и ошибок тем болеепри таком подходе
ronin
постоялец
 
Сообщения: 174
Зарегистрирован: 27.01.2010 00:14:46

Re: Вопрос по потокам TThread

Сообщение dunin » 18.02.2010 16:51:04

ronin писал(а):...как раз там таких проблем не наблюдал, просто создал поток, запустил, и никакой нагрузки на проц. писал по примерам из книг Архангельского, у него...

Ага. Знакомая фамилия. Кажется ситуация начинает проясняться... ;)
http://www.delphikingdom.com/asp/viewit ... logid=1082
Аватара пользователя
dunin
энтузиаст
 
Сообщения: 634
Зарегистрирован: 02.05.2007 13:18:11
Откуда: Тољя††и

Re: Вопрос по потокам TThread

Сообщение VirtUX » 19.02.2010 10:15:36

dunin писал(а):http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1082

Повеселило :)
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Вопрос по потокам TThread

Сообщение ronin » 24.02.2010 12:20:31

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

Код: Выделить всё
procedure TGetThread.Execute;
var
  RestartPos: DWORD; //позиция с которой начинается докачка
begin
try

    try

      //инициализация переменных
      RestartPos := 0;

      //Если на винте есть файл то считаем, что нужно докачивать
      if FileExists(файл_в_который_сохраняем) then
      begin
        rcvrdata:=TFileStream.Create(файл_в_который_сохраняем,fmOpenReadWrite,fmShareExclusive);
        rcvrdata.Seek(FileSize(файл_в_который_сохраняем),soBeginning);
        RestartPos := FileSize(файл_в_который_сохраняем);
      end
      else
      begin
        rcvrdata:=TFileStream.Create(файл_в_который_сохраняем,fmCreate,fmShareExclusive);
      end;

      //устанавливаем позицию в файле для докачки
      if RestartPos > 0 then begin
        MainForm.idHttp1.Request.ContentRangeStart:=RestartPos;
      end;

      //загрузка файла
      MainForm.idHttp1.Get(URL_скачиваемого_файла, rcvrdata);

    except

   //обработка ошибок

    end;

finally
  rcvrdata.Free;
end;
end;


программа качает только один блок и останавливается, т.е. получается как бы выполняется один проход и всё, пытался использовать конструкцию repeat until Terminated, вроде работает как надо, но не происходит остановки после окончания размера файла, который я получаю по Response.ContentLength, т.е. получается проблема с докачкой файла, причём после превышения размера файла на сервере программа продолжает что то писать в файловый поток, и компонент idHTTP показывает что AWorkCount в событии IdHTTP1Work(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64) не равен нулю.

Объясните пожалуйста мне дураку почему

1) не выполняется полная закачка файла в потоке, почему нужно использовать repeat?
2) не работает докачка файла, точнее программа продолжает что то писать в файловый поток, либо как остановить скачку при окончании файла?
3) что нужно использовать при установке позиции в скачиваемом файле Request или Response? правильно ли я делаю докачку файла?

P.S. пересмотрел кучу вариантов реализации данной функции (скачка с докачиванием файла), не хватает маргарина в голове, сильно не ругайте за кучу вопросов не по теме

Добавлено спустя 26 минут 24 секунды:
Забыл добавить, что поставив данный код на нажатие кнопки, а не в поток, закачка файла происходит до конца (без использования докачки), в потоке же нет
ronin
постоялец
 
Сообщения: 174
Зарегистрирован: 27.01.2010 00:14:46

Re: Вопрос по потокам TThread

Сообщение Mr.Smart » 24.02.2010 12:54:47

Поместите код докачки в цикл.
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Вопрос по потокам TThread

Сообщение ronin » 24.02.2010 13:47:56

Поместите код докачки в цикл.


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

основной вопрос почему при использовании кода в основном потоке приложения на нажатие кнопки закачка выполняется полностью (функция Get), а в потоке нужен цикл?

и второй вопрос - почему не останавливается закачка? пытался поставить проверку на соответствие размера файлового потока размеру файла на сервере, но так как после окончания размера файла закачка продолжается и нужный размер не попадает в условие проверки (качает по 7-11 кб за раз и значение размера может не попасть в проверяемый результат), останов закачки не происходит

P.S. мне казалось после окончания файла на сервере закачка должна останавливаться, так как это и происходит в нормальных условиях (не в потоке)
ronin
постоялец
 
Сообщения: 174
Зарегистрирован: 27.01.2010 00:14:46

Re: Вопрос по потокам TThread

Сообщение and » 24.02.2010 18:06:21

ronin писал(а):программа качает только один блок и останавливается, т.е. получается как бы выполняется один проход и всё
...
1) не выполняется полная закачка файла в потоке, почему нужно использовать repeat?
Всё правильно: процедура Execute дошла до своего End - следовательно, нить считается выполнившей свою задачу и убивается.
ronin писал(а):пытался использовать конструкцию repeat until Terminated, вроде работает как надо, но не происходит остановки после окончания размера файла
А откуда кремний знает, что для Вас именно закачка последнего блока является сигналом о достижении цели? "Компьютер железный, он делает то, что Вы приказали, а не то, чего Вы хотели на самом деле". Посему:
ronin писал(а):как остановить скачку при окончании файла?
- сказать в соответствующем месте Terminate (или terminated:=true). Если MainForm.idHttp1.Get возвращает размер скачанного этим вызовом блока, то примерно так:
terminated:=restartPos+MainForm.idHttp1.Get>=размер_файла_на_сервере.
Аватара пользователя
and
постоялец
 
Сообщения: 124
Зарегистрирован: 16.09.2009 17:11:01
Откуда: г. Гомель, Беларусь

Re: Вопрос по потокам TThread

Сообщение ronin » 24.02.2010 22:04:18

Всё правильно: процедура Execute дошла до своего End - следовательно, нить считается выполнившей свою задачу и убивается.


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

Код: Выделить всё
OnButtonClick()
var rcv:TMemoryStream;
begin

rcv:=TMemoryStream.Create;

idHTTP.Get(url, rcv);

if rcv.size>0 then rcv.SaveToFile(Filename);

rcv.Free;

end;


соответственно только по окончании скачивания файла произойдёт сохранение Stream в файл, так почему в потоке происходит скачивание только одного блока и необходимо выполнять repeat пока не будет закачан весь файл? как работает процедура Execute я до сих пор не понимаю, причём в сети постоянно вижу такой пример

Код: Выделить всё
procedure TDownLoader.Execute;
var
  http:TIdHTTP;
  str:TFileStream;
begin
  //Создим класс для закачки
  http:=TIdHTTP.Create(nil);
  //каталог, куда файл положить
  ForceDirectories(ExtractFileDir(ToFolder));
  //Поток для сохранения
  str:=TFileStream.Create(ToFolder, fmCreate);
  try
    //Качаем
    http.Get(url,str);
  finally
    //Нас учили чистить за собой
    http.Free;
    str.Free;
end;

end;


здесь же нет никакого repeat или while

сказать в соответствующем месте Terminate (или terminated:=true). Если MainForm.idHttp1.Get возвращает размер скачанного этим вызовом блока, то примерно так:
terminated:=restartPos+MainForm.idHttp1.Get>=размер_файла_на_сервере


проблема в том что по окончании размера файла функция продолжает качать, причём байты реально передаются, и предаются они порциями определённых размеров, если я поставлю указанное вами условие, то получается что размер скачанной информации может оказаться больше чем сам файл на сервере
restartPos+MainForm.idHttp1.Get>=размер_файла_на_сервере
остановка произойдёт. но размер скачанного файла окажется например на 7 килобайт больше

почему происходит дальнейшая закачка я не понимаю :(
ronin
постоялец
 
Сообщения: 174
Зарегистрирован: 27.01.2010 00:14:46

Re: Вопрос по потокам TThread

Сообщение and » 24.02.2010 23:01:00

2ronin: тогда трассируйте поведение функции TIdHTTP.Get в основной нити и другой. Разница (баг?) imho там - где-то в реализации TIdHTTP (возможно, не в самОм .Get).
Для проверки попробуйте обернуть этот вызов в Synchronize.
Аватара пользователя
and
постоялец
 
Сообщения: 124
Зарегистрирован: 16.09.2009 17:11:01
Откуда: г. Гомель, Беларусь


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 21

Рейтинг@Mail.ru