Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 06.01.2018, 15:56   #1
KBO
Форумчанин
 
Регистрация: 11.06.2010
Сообщений: 525
По умолчанию Чтение файла в потоке. Не понятно что жрет память.

Доброе время суток.
Есть программа, которая генерирует лог в диапазоне от 1 до 10 секунд (каждые).
Моя программа читает лог каждые 10сек.
Чтоб не было ошибки:

«Cannot open file …. процесс не может получить доступ к файлу, так как этот файл занят другим процессом.»

Решил вынести чтение лога в отдельный поток.

Код:
TFileReadThread = class(TThread)
    private
    { Private declarations }
    PathFile: string;
  protected
    procedure Execute; override;
  public
    constructor Create(APathFile: String);      
  end;

var
  FileReadThread: TFileReadThread;


constructor TFileReadThread.Create(APathFile: String);
begin
  inherited Create(False);
  PathFile := APathFile;
end;

procedure TFileReadThread.Execute;
var
  LFile: TStringList;
  LIndex, LIndex1, LNumGPU, L_Length: integer;
  LValue, LStringParams: string;
  LValueTrue: boolean;
begin
  while not Terminated do
  begin
    try
      FMain.lValueStatus.Caption := 'File begin reading';
      FMain.lValueStatus.Font.Color := clGreen;
      LFile := TStringList.Create;
      LFile.LoadFromFile(PathFile);                              
      L_Length := LFile.Count-1;
      LStringParams := '';
      LValueTrue := false;
      LValue := '';
      LNumGPU := 0;


      for LIndex := L_Length downto 0 do
        if Pos('ETH: GPU0', LFile.Strings[LIndex]) <> 0 then
        begin
          FMain.edGPU0.Clear;
          FMain.edGPU1.Clear;
          LStringParams := LFile.Strings[LIndex];
          for LIndex1 := 0 to length(LStringParams) do
          begin
            if (LStringParams[LIndex1] in ['0'..'9']) then
              LValue := LValue+LStringParams[LIndex1]
            else
              if ((LStringParams[LIndex1] = '.')
                or (LStringParams[LIndex1] = ','))
                and (LValue <> '') then
              begin
                LValue := LValue+'.';
                LValueTrue := true;
              end
              else 
              begin
                if (LStringParams[LIndex1] = ' ')
                  and (LValueTrue) then
                begin
                  if (FMain.edGPU0.Text = '')
                    and (LNumGPU = 0) then
                    FMain.edGPU0.Text := LValue;
                  if (FMain.edGPU1.Text = '')
                    and (LNumGPU = 1)  then
                    FMain.edGPU1.Text := LValue;  
                  inc(LNumGPU);  
                end  
                else LValueTrue := false;
                LValue := '';  
              end;
          end;  
          break;
        end;

      LValue := '';
      LNumGPU := 0;
      for LIndex := L_Length downto 0 do
        if Pos('GPU0 t=', LFile.Strings[LIndex]) <> 0 then
        begin
          FMain.edTemp0.Clear;
          FMain.edTemp1.Clear;
          LStringParams := LFile.Strings[LIndex];
          for LIndex1 := 0 to length(LStringParams) do
          begin
            if (LStringParams[LIndex1] in ['0'..'9']) then
              LValue := LValue+LStringParams[LIndex1]
            else
              begin
                if (LStringParams[LIndex1] = 'C') then
                begin
                  if (FMain.edTemp0.Text = '')
                    and (LNumGPU = 0) then
                    FMain.edTemp0.Text := LValue;
                  if (FMain.edTemp1.Text = '')
                    and (LNumGPU = 1)  then
                    FMain.edTemp1.Text := LValue;  
                  inc(LNumGPU);  
                end  
                else LValueTrue := false;
                LValue := '';  
              end;
          end;  
          break;
        end;
         FMain.lValueStatus.Caption := 'File end reading';
         FreeAndNil(LFile);
          
         FileReadThread.Terminate;
         FileReadThread.WaitFor;
         FreeAndNil(FileReadThread);
         inherited Destroy;
    except
    on E: Exception do
      begin
        FMain.lValueStatus.Caption := 'Not access to file';
        FMain.lValueStatus.Font.Color := clRed;
        LFile.Free;
      end
    end;
  end;  
end;
Вызываю поток каждые 10сек. С помощью «Timer»
Код:
procedure TFMain.tPollDirectoryTimer(Sender: TObject);
var
  LNewFile: TSearchRec;
  LFileTime, LFileSize: integer;
  LPathFile, LFileName: string;
begin
  lValueStatus.Font.Color := clGreen;  
  LFileTime := 0;
  if FindFirst(edPathLog.Text+'*_log.txt', faAnyFile - faDirectory - faVolumeID, LNewFile) = 0 then
  repeat
    if LFileTime = 0 then
    begin
      LFileTime := LNewFile.Time;
      LFileSize := LNewFile.Size;
      LFileName := LNewFile.Name;
    end;
    
    if LFileTime < LNewFile.Time then
    begin
      LFileTime := LNewFile.Time;
      LFileSize := LNewFile.Size; 
      LFileName := LNewFile.Name; 
    end;  
  until FindNext(LNewFile) <> 0;
  FindClose(LNewFile);

  FileReadThread := TFileReadThread.Create(edPathLog.Text+LFileName);
  FileReadThread.Priority := tpNormal;

    
  laFileName.Caption := LFileName; 
  laFileTime.Caption := DateTimeToStr(FileDateToDateTime(LFileTime));
  laFileSize.Caption := IntToStr(LFileSize);

  if Pr_OldTime <> 0 then
  begin  
    if (Pr_OldTime = LFileTime) 
      and (Pr_OldSize = LFileSize) then
    begin
      EndPointVolume.SetMasterVolumeLevelScalar(1, nil);    
      SOURCE_BEEP(LOG);
      
      WRITE_LOG_FILE;
    end;
  end;
  Pr_OldName := LFileName;
  Pr_OldSize := LFileSize;
  Pr_OldTime := LFileTime;
end;
В результате я создаю только поток («FileReadThread») и «LFile», но я их все уничтожаю.

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

Спасибо за ответ.
KBO вне форума Ответить с цитированием
Старый 06.01.2018, 16:06   #2
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 19,042
По умолчанию

Стринглист освобождаешь по исключению, а без исключения кто это делать будет?
Код:
FMain.edGPU0.Text := LValue;
Из-за того и подобного рано или поздно рухнет основной поток. Низзя к vcl из потока без синхронизации обращаться

Destroy из Execute это как?
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 06.01.2018, 16:47   #3
KBO
Форумчанин
 
Регистрация: 11.06.2010
Сообщений: 525
По умолчанию

Цитата:
Сообщение от Аватар Посмотреть сообщение
Стринглист освобождаешь по исключению, а без исключения кто это делать будет?
Нет, стринглист, я освобождаю и в исключении
Код:
LFile.Free;
и в потоке
Код:
FreeAndNil(LFile);
хотя и разными методами (посмотрите внимательно)

Да синхронизацию я забыл - спасибо наплмнили
и с "Destroy" намутил... уберу его

Последний раз редактировалось KBO; 06.01.2018 в 16:52.
KBO вне форума Ответить с цитированием
Старый 06.01.2018, 20:01   #4
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,515
По умолчанию

Цитата:
Код:
         FileReadThread.Terminate;
         FileReadThread.WaitFor;
         FreeAndNil(FileReadThread);
         inherited Destroy;
это что попытка остановить и разрушить поток из самого потока?
для самостоятельной остановки достаточно просто дойти до конца процедуры(убрав первоначальный цикл)

или наиболее разумное предложение.
наоборот оставить цикл и убрать(Timer) кучу новых потоков.
а в цикле при необходимости добавить sleep()
и тогда имеем ОДИН нормальный бесконечный(постоянно работающий) поток и можем при необходимости остановить его извне
Код:
 FileReadThread.Terminate;
как только поток сможет проработать дольше чем до следующего запуска.
то остановлен и разрушен будет совсем другой поток, а старый уйдет в небытие с потерей (утечкой) ресурсов.
глобальная переменная в потоке почти тоже что и VCL в нем.
программа — запись алгоритма на языке понятном транслятору
evg_m на форуме Ответить с цитированием
Старый 06.01.2018, 21:17   #5
Alex11223
Старожил
 
Аватар для Alex11223
 
Регистрация: 12.01.2011
Сообщений: 19,500
По умолчанию

А я один не понял каким образом поток решает проблему с ошибкой доступа к файлу?
Ушел с форума, https://www.programmersforum.rocks, alex.pantec@gmail.com, https://github.com/AlexP11223
ЛС отключены Аларом.
Alex11223 вне форума Ответить с цитированием
Старый 06.01.2018, 22:09   #6
KBO
Форумчанин
 
Регистрация: 11.06.2010
Сообщений: 525
По умолчанию

Цитата:
Сообщение от Alex11223 Посмотреть сообщение
А я один не понял каким образом поток решает проблему с ошибкой доступа к файлу?
Я не то имел ввиду - неправильно выразился, там не в потоке дело, просто не пользовался конструкцией "try... except"
KBO вне форума Ответить с цитированием
Старый 06.01.2018, 22:11   #7
KBO
Форумчанин
 
Регистрация: 11.06.2010
Сообщений: 525
По умолчанию

Цитата:
Сообщение от evg_m Посмотреть сообщение
это что попытка остановить и разрушить поток из самого потока?
bиз 4-х строк, оставил просто "Terminate".
Код:
procedure TFileReadThread.Execute;
var
  LFile: TStringList;
  LIndex, LIndex1, LNumGPU, L_Length: integer;
  LValue, LStringParams: string;
  LValueTrue: boolean;
begin
  while not Terminated do
  begin
    try
      Pr_Status := 'File begin reading';
      Pr_Status_Color := clGreen;
      Synchronize(UpdStatus);

      LFile := TStringList.Create;
      LFile.LoadFromFile(PathFile);                              
      L_Length := LFile.Count-1;
      LStringParams := '';
      LValueTrue := false;
      LValue := '';
      LNumGPU := 0;

      for LIndex := L_Length downto 0 do
        if Pos('ETH: GPU0', LFile.Strings[LIndex]) <> 0 then
        begin
          LStringParams := LFile.Strings[LIndex];
          for LIndex1 := 0 to length(LStringParams) do
          begin
            if (LStringParams[LIndex1] in ['0'..'9']) then
              LValue := LValue+LStringParams[LIndex1]
            else
              if ((LStringParams[LIndex1] = '.')
                or (LStringParams[LIndex1] = ','))
                and (LValue <> '') then
              begin
                LValue := LValue+'.';
                LValueTrue := true;
              end
              else 
              begin
                if (LStringParams[LIndex1] = ' ')
                  and (LValueTrue) then
                begin
                  if (FMain.edGPU0.Text = '')
                    and (LNumGPU = 0) then
                    begin
                      Pr_ValGPU := LValue;
                      Synchronize(UpdGPU0);   
                    end;
                  if (FMain.edGPU1.Text = '')
                    and (LNumGPU = 1) then
                    begin
                      Pr_ValGPU := LValue;
                      Synchronize(UpdGPU1);   
                    end;
                  inc(LNumGPU);  
                end  
                else LValueTrue := false;
                LValue := '';  
              end;
          end;  
          break;
        end;

      LValue := '';
      LNumGPU := 0;
      for LIndex := L_Length downto 0 do
        if Pos('GPU0 t=', LFile.Strings[LIndex]) <> 0 then
        begin
          LStringParams := LFile.Strings[LIndex];
          for LIndex1 := 0 to length(LStringParams) do
          begin
            if (LStringParams[LIndex1] in ['0'..'9']) then
              LValue := LValue+LStringParams[LIndex1]
            else
              begin
                if (LStringParams[LIndex1] = 'C') then
                begin
                  if (FMain.edTemp0.Text = '')
                    and (LNumGPU = 0) then
                    begin
                      Pr_ValTemp := LValue;
                      Synchronize(UpdTemp0);   
                    end;
                  if (FMain.edTemp1.Text = '')
                    and (LNumGPU = 1)  then
                    begin
                      Pr_ValTemp := LValue;
                      Synchronize(UpdTemp1);   
                    end;
                  inc(LNumGPU);  
                end  
                else LValueTrue := false;
                LValue := '';  
              end;
          end;  
          break;
        end;
        Pr_Status := 'File end reading';
        Pr_Status_Color := clGreen;
        Synchronize(UpdStatus);
        FreeAndNil(LFile);
        FileReadThread.Terminate;
    except
    on E: Exception do
      begin
        Pr_Status := 'Not access to file';
        Pr_Status_Color := clRed;
        Synchronize(UpdStatus);
        FreeAndNil(LFile);
      end
    end;
  end;  
end;
Хотя память занимаемая программой всеравно продолжает РОСТИ, медленно но растет.

А "Timer", использова просто для того чтоб через каждые 10сек,

Последний раз редактировалось KBO; 06.01.2018 в 22:29.
KBO вне форума Ответить с цитированием
Старый 06.01.2018, 22:22   #8
KBO
Форумчанин
 
Регистрация: 11.06.2010
Сообщений: 525
По умолчанию

Цитата:
Сообщение от evg_m Посмотреть сообщение
а в цикле при необходимости добавить sleep()
т.е. если я вас правильно понял, вы предлагаете присто при создании формы создать поток и его зациклить с "sleep(10000)" например 10сек?
и если что потом я могу с главного потока изменять значение "sleep"
KBO вне форума Ответить с цитированием
Старый 07.01.2018, 09:56   #9
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,515
По умолчанию

Цитата:
если что потом я могу с главного потока изменять значение "sleep"
почему бы и нет, только надо помнить(знать,понимать) что изменение задержки проявиться не сразу, а только со следующей итерации цикла.

Код:
        FileReadThread.Terminate;
это остановка не самого себя, а последнего запущенного(того который был ПОСЛЕДНИМ записан в данную переменную)
Код:
  FileReadThread := TFileReadThread.Create(edPathLog.Text+LFileName);
Код:
self.Terminate;
но это всего лишь
Код:
self.terminated:=true;
программа — запись алгоритма на языке понятном транслятору

Последний раз редактировалось evg_m; 07.01.2018 в 10:26.
evg_m на форуме Ответить с цитированием
Старый 07.01.2018, 21:14   #10
KBO
Форумчанин
 
Регистрация: 11.06.2010
Сообщений: 525
По умолчанию

и всеже я хочу понять что сжирает память.
БЕЗ следующих строк (использующихся в потоке), память НЕ теряется
Код:
      for LIndex := L_Length downto 0 do
        if Pos('ETH: GPU0', LFile.Strings[LIndex]) <> 0 then
        begin
          LStringParams := LFile.Strings[LIndex];
          for LIndex1 := 0 to length(LStringParams) do
          begin
            if (LStringParams[LIndex1] in ['0'..'9']) then
              LValue := LValue+LStringParams[LIndex1]
            else
              if ((LStringParams[LIndex1] = '.')
                or (LStringParams[LIndex1] = ','))
                and (LValue <> '') then
              begin
                LValue := LValue+'.';
                LValueTrue := true;
              end
              else 
              begin
                if (LStringParams[LIndex1] = ' ')
                  and (LValueTrue) then
                begin
                  if (FMain.edGPU0.Text = '')
                    and (LNumGPU = 0) then
                    begin
                      Pr_ValGPU := LValue;
                      Synchronize(UpdGPU0);   
                    end;
                  if (FMain.edGPU1.Text = '')
                    and (LNumGPU = 1) then
                    begin
                      Pr_ValGPU := LValue;
                      Synchronize(UpdGPU1);   
                    end;
                  inc(LNumGPU);  
                end  
                else LValueTrue := false;
                LValue := '';  
              end;
          end;  
          break;
        end;

      LValue := '';
      LNumGPU := 0;
      for LIndex := L_Length downto 0 do
        if Pos('GPU0 t=', LFile.Strings[LIndex]) <> 0 then
        begin
          LStringParams := LFile.Strings[LIndex];
          for LIndex1 := 0 to length(LStringParams) do
          begin
            if (LStringParams[LIndex1] in ['0'..'9']) then
              LValue := LValue+LStringParams[LIndex1]
            else
              begin
                if (LStringParams[LIndex1] = 'C') then
                begin
                  if (FMain.edTemp0.Text = '')
                    and (LNumGPU = 0) then
                    begin
                      Pr_ValTemp := LValue;
                      Synchronize(UpdTemp0);   
                    end;
                  if (FMain.edTemp1.Text = '')
                    and (LNumGPU = 1)  then
                    begin
                      Pr_ValTemp := LValue;
                      Synchronize(UpdTemp1);   
                    end;
                  inc(LNumGPU);  
                end  
                else LValueTrue := false;
                LValue := '';  
              end;
          end;  
          break;
        end;
но тут ничего такого нет, чтоб захламлять и не отдавать память

Последний раз редактировалось KBO; 07.01.2018 в 21:23.
KBO вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Пустое приложение жрет память AlexAES C++ Builder 0 23.10.2017 22:29
Что быстрее, запись и чтение реестра или файла? lollollollol Общие вопросы Delphi 13 21.11.2015 09:47
Цикл грузит процессор и жрет память. DIgorevich Общие вопросы Delphi 3 29.07.2015 10:44
WEB-приложение жрет память alexey_kip Java для Web (EE, Servlet, JSP, Tomcat, Spring MVC) 4 29.05.2015 16:55
Что за процесс такой. Жрет 95-97-100% ресурсов CPU kzld Windows 7 11.02.2014 05:33