Вопрос по потокам TThread
Модератор: Модераторы
Вопрос по потокам TThread
Вопрос в следующем - при использовании (запуске) потока приложение грузит систему процентов на 30-40, после остановки потока всё ок, нагрузка падает до нуля. Попытался сделать пустое приложение, воткнул конструкции создания и запуска потоков, в общем всё как надо, запустил приложение, по нажатию кнопки при создании потока и последующего его запуска наблюдаю такой эффект.
Проверил приложение на двух системах, эффект тот же. Примера кода не привожу, там в принципе ничего экстраординарного, хочется знать может кто сталкивался с такими проблемами? или только я такой?
PS варьировать приоритет потока пробовал, не влияет на результат.
ОС: Ubuntu 9.10 (karmic)
Lazarus: 0.9.28.2.0 beta
FPC: 2.2.4
Добавлено спустя 1 минуту 24 секунды:
да .ещё забыл сказать что в потоке никаких действий не выполняется, просто запуск (создание) и потом останов (уничтожение) потока
Проверил приложение на двух системах, эффект тот же. Примера кода не привожу, там в принципе ничего экстраординарного, хочется знать может кто сталкивался с такими проблемами? или только я такой?
PS варьировать приоритет потока пробовал, не влияет на результат.
ОС: Ubuntu 9.10 (karmic)
Lazarus: 0.9.28.2.0 beta
FPC: 2.2.4
Добавлено спустя 1 минуту 24 секунды:
да .ещё забыл сказать что в потоке никаких действий не выполняется, просто запуск (создание) и потом останов (уничтожение) потока
а вы поставьте sleep
почитал материалы в сети, нашёл такой вариант решения, а не подскажете как это работает, а то я немного не догоняю
что такое sleep понятно, но почему в потоке? и ставить надо в процедуре execute?
Добавлено спустя 45 секунд:
просто в delphi под виндой такого вроде не надо было делать
Добавлено спустя 45 секунд:
просто в delphi под виндой такого вроде не надо было делать
примерно так должно быть
Код: Выделить всё
while //поток живет
// делаем что то в потоке
sleep(100); // засыпаем на 100 мс
end;
Можно вставить и sleep(1).
Нужно понять, что sleep(1) сообщает ОС о жесткой остановке потока, и тем самым освобождая ресурс ЦП. В Delphi 7 такая же ситуация. Может сейчас они там и добавили автоматически, но - это, помоему, вводит в заблуждение, а не помогает разработчику.
Нужно понять, что sleep(1) сообщает ОС о жесткой остановке потока, и тем самым освобождая ресурс ЦП. В Delphi 7 такая же ситуация. Может сейчас они там и добавили автоматически, но - это, помоему, вводит в заблуждение, а не помогает разработчику.
В Delphi 7 такая же ситуация
как раз там таких проблем не наблюдал, просто создал поток, запустил, и никакой нагрузки на проц. писал по примерам из книг Архангельского, у него тоже ничего такого не упоминается, это какая то специфика IDE или платформы?
но - это, помоему, вводит в заблуждение, а не помогает разработчику.
а что здесь такого плохого? я не чувствую какого то дискомфорта под виндой, и ошибок тем болеепри таком подходе
- dunin
- энтузиаст
- Сообщения: 634
- Зарегистрирован: 02.05.2007 13:18:11
- Откуда: Тољя††и
- Контактная информация:
ronin писал(а):...как раз там таких проблем не наблюдал, просто создал поток, запустил, и никакой нагрузки на проц. писал по примерам из книг Архангельского, у него...
Ага. Знакомая фамилия. Кажется ситуация начинает проясняться...
http://www.delphikingdom.com/asp/viewit ... logid=1082
dunin писал(а):http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1082
Повеселило
Замучался я с этим потоком, совсем запутался, прочитал уже кучу литературы, но что то не могу понять как он работает. В потоке осуществляю закачку файла с докачкой, код такой
программа качает только один блок и останавливается, т.е. получается как бы выполняется один проход и всё, пытался использовать конструкцию repeat until Terminated, вроде работает как надо, но не происходит остановки после окончания размера файла, который я получаю по Response.ContentLength, т.е. получается проблема с докачкой файла, причём после превышения размера файла на сервере программа продолжает что то писать в файловый поток, и компонент idHTTP показывает что AWorkCount в событии IdHTTP1Work(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64) не равен нулю.
Объясните пожалуйста мне дураку почему
1) не выполняется полная закачка файла в потоке, почему нужно использовать repeat?
2) не работает докачка файла, точнее программа продолжает что то писать в файловый поток, либо как остановить скачку при окончании файла?
3) что нужно использовать при установке позиции в скачиваемом файле Request или Response? правильно ли я делаю докачку файла?
P.S. пересмотрел кучу вариантов реализации данной функции (скачка с докачиванием файла), не хватает маргарина в голове, сильно не ругайте за кучу вопросов не по теме
Добавлено спустя 26 минут 24 секунды:
Забыл добавить, что поставив данный код на нажатие кнопки, а не в поток, закачка файла происходит до конца (без использования докачки), в потоке же нет
Код: Выделить всё
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 секунды:
Забыл добавить, что поставив данный код на нажатие кнопки, а не в поток, закачка файла происходит до конца (без использования докачки), в потоке же нет
Поместите код докачки в цикл.
Поместите код докачки в цикл.
я же написал что помещал, закачка работает, но не останавливается там где должна (судя по размеру файла на сервере)
основной вопрос почему при использовании кода в основном потоке приложения на нажатие кнопки закачка выполняется полностью (функция Get), а в потоке нужен цикл?
и второй вопрос - почему не останавливается закачка? пытался поставить проверку на соответствие размера файлового потока размеру файла на сервере, но так как после окончания размера файла закачка продолжается и нужный размер не попадает в условие проверки (качает по 7-11 кб за раз и значение размера может не попасть в проверяемый результат), останов закачки не происходит
P.S. мне казалось после окончания файла на сервере закачка должна останавливаться, так как это и происходит в нормальных условиях (не в потоке)
Всё правильно: процедура Execute дошла до своего End - следовательно, нить считается выполнившей свою задачу и убивается.ronin писал(а):программа качает только один блок и останавливается, т.е. получается как бы выполняется один проход и всё
...
1) не выполняется полная закачка файла в потоке, почему нужно использовать repeat?
А откуда кремний знает, что для Вас именно закачка последнего блока является сигналом о достижении цели? "Компьютер железный, он делает то, что Вы приказали, а не то, чего Вы хотели на самом деле". Посему:ronin писал(а):пытался использовать конструкцию repeat until Terminated, вроде работает как надо, но не происходит остановки после окончания размера файла
- сказать в соответствующем месте Terminate (или terminated:=true). Если MainForm.idHttp1.Get возвращает размер скачанного этим вызовом блока, то примерно так:ronin писал(а):как остановить скачку при окончании файла?
terminated:=restartPos+MainForm.idHttp1.Get>=размер_файла_на_сервере.
Всё правильно: процедура 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>=размер_файла_на_сервере
проблема в том что по окончании размера файла функция продолжает качать, причём байты реально передаются, и предаются они порциями определённых размеров, если я поставлю указанное вами условие, то получается что размер скачанной информации может оказаться больше чем сам файл на сервере
остановка произойдёт. но размер скачанного файла окажется например на 7 килобайт большеrestartPos+MainForm.idHttp1.Get>=размер_файла_на_сервере
почему происходит дальнейшая закачка я не понимаю
2ronin: тогда трассируйте поведение функции TIdHTTP.Get в основной нити и другой. Разница (баг?) imho там - где-то в реализации TIdHTTP (возможно, не в самОм .Get).
Для проверки попробуйте обернуть этот вызов в Synchronize.
Для проверки попробуйте обернуть этот вызов в Synchronize.
