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

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

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

Ответить
ronin
постоялец
Сообщения: 174
Зарегистрирован: 26.01.2010 23:14:46

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

Сообщение ronin »

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

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

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

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

Добавлено спустя 1 минуту 24 секунды:
да .ещё забыл сказать что в потоке никаких действий не выполняется, просто запуск (создание) и потом останов (уничтожение) потока
Аватара пользователя
hinst
энтузиаст
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Сообщение hinst »

а вы поставьте sleep
ronin
постоялец
Сообщения: 174
Зарегистрирован: 26.01.2010 23:14:46

Сообщение ronin »

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

Добавлено спустя 45 секунд:
просто в delphi под виндой такого вроде не надо было делать
eevee
новенький
Сообщения: 63
Зарегистрирован: 29.12.2009 16:52:44
Откуда: Саратов

Сообщение eevee »

примерно так должно быть

Код: Выделить всё

while //поток живет
  // делаем что то в потоке
  sleep(100); // засыпаем на 100 мс
end;
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

Можно вставить и sleep(1).
Нужно понять, что sleep(1) сообщает ОС о жесткой остановке потока, и тем самым освобождая ресурс ЦП. В Delphi 7 такая же ситуация. Может сейчас они там и добавили автоматически, но - это, помоему, вводит в заблуждение, а не помогает разработчику.
ronin
постоялец
Сообщения: 174
Зарегистрирован: 26.01.2010 23:14:46

Сообщение ronin »

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


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

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


а что здесь такого плохого? я не чувствую какого то дискомфорта под виндой, и ошибок тем болеепри таком подходе
Аватара пользователя
dunin
энтузиаст
Сообщения: 634
Зарегистрирован: 02.05.2007 13:18:11
Откуда: Тољя††и
Контактная информация:

Сообщение dunin »

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

Ага. Знакомая фамилия. Кажется ситуация начинает проясняться... ;)
http://www.delphikingdom.com/asp/viewit ... logid=1082
Аватара пользователя
VirtUX
энтузиаст
Сообщения: 880
Зарегистрирован: 05.02.2008 09:52:19
Откуда: Крым, Алушта

Сообщение VirtUX »

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

Повеселило :)
ronin
постоялец
Сообщения: 174
Зарегистрирован: 26.01.2010 23:14:46

Сообщение ronin »

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

Код: Выделить всё

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 секунды:
Забыл добавить, что поставив данный код на нажатие кнопки, а не в поток, закачка файла происходит до конца (без использования докачки), в потоке же нет
Mr.Smart
долгожитель
Сообщения: 1796
Зарегистрирован: 29.03.2008 00:01:11
Откуда: из леса!

Сообщение Mr.Smart »

Поместите код докачки в цикл.
ronin
постоялец
Сообщения: 174
Зарегистрирован: 26.01.2010 23:14:46

Сообщение ronin »

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


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

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

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

P.S. мне казалось после окончания файла на сервере закачка должна останавливаться, так как это и происходит в нормальных условиях (не в потоке)
Аватара пользователя
and
постоялец
Сообщения: 124
Зарегистрирован: 16.09.2009 17:11:01
Откуда: г. Гомель, Беларусь

Сообщение and »

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

Сообщение ronin »

Всё правильно: процедура 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 килобайт больше

почему происходит дальнейшая закачка я не понимаю :(
Аватара пользователя
and
постоялец
Сообщения: 124
Зарегистрирован: 16.09.2009 17:11:01
Откуда: г. Гомель, Беларусь

Сообщение and »

2ronin: тогда трассируйте поведение функции TIdHTTP.Get в основной нити и другой. Разница (баг?) imho там - где-то в реализации TIdHTTP (возможно, не в самОм .Get).
Для проверки попробуйте обернуть этот вызов в Synchronize.
Ответить