Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > ОС и железо
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 14.04.2018, 15:21
nixon232 nixon232 вне форума
Активный
 
Регистрация: 26.01.2014
Сообщения: 282
Версия Delphi: delphi xe4
Репутация: выкл
По умолчанию Поток + Set|KillTimmer

Подскажите в чем может быть проблема.
Обработчик таймера
Код:
procedure TЬForm.WMTimer(var Msg: TWMTimer);
begin
  try
    try

      Thr.initWork(Msg.TimerID);
      //  ShowMessage(BoolToStr(KillTimer(Self.Handle, msg.TimerID), True));
      Msg.Result := 0;

    except

    end;
  finally
    KillTimer(Handle, Msg.TimerID);
    inherited;
  end;

end;
InitWork
Код:
begin
  FLock.Enter;
  try
    if not FOnTime then
    begin
      fOnTime:=True;
      ....
      fOnTime:=false;

    end;

  finally
    FLock.Leave
  end;
end;
все работает хорошо, если таймер создается 1, если таймеров 2+, то FOnTime всегда true. Таймеры создаются с достаточной задержкой друг от друга. Лог и время тика каждого таймера прилагаю.
Код:
[14:11:42:253] Add Worker: Id: 1, Time: 7000 
[14:11:42:759] Add Worker: Id: 2, Time: 8500 
[14:11:43:264] Add Worker: Id: 3, Time: 10500 
Формально будет всегда False. FOnTime наступить не должно и проверку можно убрать, но вопрос не в этом, а почему оно наступает

Последний раз редактировалось nixon232, 14.04.2018 в 15:26.
Ответить с цитированием
  #2  
Старый 15.04.2018, 12:57
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

По Вашему коду остается только догадываться, что Вы пытаетесь сделать.
Могу предположить, что используется один дополнительный поток Thr и для него инициализирована одна критическая секция FLock. Для чего Вам FOnTime, и FLock?
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.
Ответить с цитированием
  #3  
Старый 15.04.2018, 17:53
nixon232 nixon232 вне форума
Активный
 
Регистрация: 26.01.2014
Сообщения: 282
Версия Delphi: delphi xe4
Репутация: выкл
По умолчанию

Цитата:
Сообщение от dr. F.I.N.
По Вашему коду остается только догадываться, что Вы пытаетесь сделать.
Могу предположить, что используется один дополнительный поток Thr и для него инициализирована одна критическая секция FLock. Для чего Вам FOnTime, и FLock?
Флаг работы с данными. Вот и возник вопрос, почему этот флаг не сбрасывается после работы, хотя по дебагеру там явно присваивается False. Тут больше не к коду вопросы, а я просто что-то не понимаю.
Я уже и через Property пробовал и все равно при втором проходе возвращает True. Хотя, по логике, если там True, то я бы уперся в крит. секцию.

Неужели нужно паузу ставить в момент смены флага?
Ответить с цитированием
  #4  
Старый 15.04.2018, 18:01
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Цитата:
Сообщение от nixon232
Флаг работы с данными. Вот и возник вопрос, почему этот флаг не сбрасывается после работы, хотя по дебагеру там явно присваивается False. Тут больше не к коду вопросы, а я просто что-то не понимаю.
Я уже и через Property пробовал и все равно при втором проходе возвращает True. Хотя, по логике, если там True, то я бы уперся в крит. секцию.

Неужели нужно паузу ставить в момент смены флага?
Для просмотра флага входите в критическую секцию? Уверены, что при просмотре флага поток не успевает сменить его значение? А может флаг не нужен совсем? Какую логику работы вы "преследуете"? В каком месте кода вы работаете с данными и где проверяете флаг?
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.

Последний раз редактировалось dr. F.I.N., 15.04.2018 в 18:12.
Ответить с цитированием
  #5  
Старый 15.04.2018, 19:00
nixon232 nixon232 вне форума
Активный
 
Регистрация: 26.01.2014
Сообщения: 282
Версия Delphi: delphi xe4
Репутация: выкл
По умолчанию

Цитата:
Сообщение от dr. F.I.N.
Для просмотра флага входите в критическую секцию? Уверены, что при просмотре флага поток не успевает сменить его значение? А может флаг не нужен совсем? Какую логику работы вы "преследуете"? В каком месте кода вы работаете с данными и где проверяете флаг?
Вы правы, в реальном коде от этого отказался, за ненадобностью т.к. сам таймер предотвращает одновременное использование. Но для общего развития хотелось бы понять причину. Шансов на то, что не успевает записать, нету т.к. второй запрос идет спустя ~2 с, а сам запрос не затратный.
Сам поток правда в цикле крутится с такой паузой в цикле
Код:
...
begin
  while not Terminated do
  begin
    case WaitForMultipleObjects(2, @FHandles[0], False, INFINITE) of
      WAIT_FAILED:
        RaiseLastOsError;
      WAIT_OBJECT_0:
        Terminate;
      WAIT_OBJECT_0 + 1:
        begin
          WaitMe(400);
...
Код:
procedure WaitMe(msc: Cardinal);
var
  Ret: Dword;
  WaitTime: TLargeInteger;
  Timer: THandle;
begin
  // sleep  without freezing
  Timer := CreateWaitableTimer(nil, True, nil);
  WaitTime := -msc * 10000; 
  SetWaitableTimer(Timer, WaitTime, 0, nil, nil, false);
  repeat
  
    Ret := MsgWaitForMultipleObjects(1, Timer, false, INFINITE, QS_ALLINPUT);
    if Ret <> (WAIT_OBJECT_0 + 1) then
      Break;
    Application.ProcessMessages;
  until false;
  if Ret <> WAIT_OBJECT_0 then
    CancelWaitableTimer(Timer);
  CloseHandle(Timer);
end;
Проверяю флаг тут же, в InitWork
Код:
type
  TThr= class(TThread)
  private
    FHandles: array[0..1] of THandle;
    FLock: TCriticalSection;
    fOnTime: Boolean;
...
procedure TThr.InitWork(id: Cardinal);
begin
  FLock.Enter;
  try
    if not FOnTime then
    begin
      fOnTime:=True;
      ....
      fOnTime:=false;
 
    end;
 
  finally
    FLock.Leave
  end;
end;
то есть грубо говоря:
Код:
 Thr.initWork(1);/// fONTime =false, все ок, заходим, меняем флаг, работаем, меняем обратно
 Thr.initWork(2);/// fONTime =true 

Последний раз редактировалось nixon232, 15.04.2018 в 19:24.
Ответить с цитированием
  #6  
Старый 15.04.2018, 19:42
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Есть подозрение, что в основном потоке вы вызываете метод объекта Thr. InitWork где должен происходить? в основном или доп потоке?
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.
Ответить с цитированием
  #7  
Старый 15.04.2018, 19:55
nixon232 nixon232 вне форума
Активный
 
Регистрация: 26.01.2014
Сообщения: 282
Версия Delphi: delphi xe4
Репутация: выкл
По умолчанию

Цитата:
Сообщение от dr. F.I.N.
Есть подозрение, что в основном потоке вы вызываете метод объекта Thr. InitWork где должен происходить? в основном или доп потоке?
Судя по тому, что он вызывается по таймеру, а таймер такой
Код:
procedure TMForm.WMTimer(var Msg: TWMTimer);
begin
**try
****try
*
******Thr.initWork(Msg.TimerID);
...
То выходит что в основном? из-за этого все проблемы? тогда как нужно корректно вызывать, чтобы он шел доп-потоком? не передавать Id, а смотреть его в InitWork, а InitWork зациклить?

Последний раз редактировалось nixon232, 15.04.2018 в 19:57.
Ответить с цитированием
  #8  
Старый 15.04.2018, 19:59
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Ну, для передачи параметра в поток можно в доп-потоке сделать цикл сообщений и отправлять туда PostThreadMessage.
Еще раз повторюсь, я просто строю догадки о том, что Вы пытаетесь сделать. Есть вероятность, что я советую лишнее.
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.
Ответить с цитированием
Этот пользователь сказал Спасибо dr. F.I.N. за это полезное сообщение:
nixon232 (15.04.2018)
  #9  
Старый 15.04.2018, 20:19
nixon232 nixon232 вне форума
Активный
 
Регистрация: 26.01.2014
Сообщения: 282
Версия Delphi: delphi xe4
Репутация: выкл
По умолчанию

Цитата:
Сообщение от dr. F.I.N.
Ну, для передачи параметра в поток можно в доп-потоке сделать цикл сообщений и отправлять туда PostThreadMessage.
Еще раз повторюсь, я просто строю догадки о том, что Вы пытаетесь сделать. Есть вероятность, что я советую лишнее.
Сейчас я хочу лишь разобраться. правильно ли я вас понял, что любое изменение (прямое) свойств запущенного потока из главной формы бессмысленны и что смысл потока в этом случае теряется?
Ну либо его стопать перед изменением?
Ваша догадка про вызов из главного потока оказалось верной, если не вызывать явно InitWork, то флаг отрабатывает.

Последний раз редактировалось nixon232, 15.04.2018 в 21:50.
Ответить с цитированием
  #10  
Старый 16.04.2018, 15:55
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Если хотите работать с объектом потока и менять его параметры или вызывать некую процедуру, можно либо создать в потоке очередь сообщений и из главного потока слать PostThreadMessage (как я уже писал), или сделать тоже самое на событиях.
Код:
type
  TThr = class (TThread)
  private
    FLock: TCriticalSection;
    FFiled: SomeType;
    FSetEvent: TEvent;
    function GetField: SomeType;
    procedure SetField(Value: SomeType);
  public
    property Field: SomeType read GetField write SetField;
  end;

function GetField: SomeType;
begin
  FLock.Enter;
  try
    Result := FField;
  finally
    FLock.Leave;
  end;
end;

procedure SetField(Value: SomeType);
begin
  FLock.Enter;
  try
    FField := Value;
  finally
    FLock.Leave;
  end;
  FSetEvent.SetEvent;
end;

procedure Ececute();
begin
  Handles[N] := FSetEvent.Handle;
  case WaitForMultiplyObjects(...) of
  Wait_Object_0 + N: {сработало событие изменения поля};
  end;
end;
Написал на коленке, могут быть ошибки. Если надо, где-то есть примерчик на сообщениях.
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.
Ответить с цитированием
Этот пользователь сказал Спасибо dr. F.I.N. за это полезное сообщение:
nixon232 (16.04.2018)
  #11  
Старый 16.04.2018, 16:14
nixon232 nixon232 вне форума
Активный
 
Регистрация: 26.01.2014
Сообщения: 282
Версия Delphi: delphi xe4
Репутация: выкл
По умолчанию

Спасибо, более чем доходчивый пример.
Ответить с цитированием
  #12  
Старый 19.04.2018, 09:27
nixon232 nixon232 вне форума
Активный
 
Регистрация: 26.01.2014
Сообщения: 282
Версия Delphi: delphi xe4
Репутация: выкл
По умолчанию

Попытался я реализовать вашу идею и что не получается. не подскажите в чем косяк?
Код:
while not Terminated do
  begin
    case WaitForMultipleObjects(3, @FHandles[0]{or @FHandles}, False , INFINITE) of
      WAIT_FAILED:
        RaiseLastOsError;
      WAIT_OBJECT_0:
        Terminate;
      WAIT_OBJECT_0 + 1:
        begin
        //some work 
        end;
      WAIT_OBJECT_0 + 2:
        begin
          AddLogEvent;// сюда мы не попадаем.
        end;
    end;
  end;

end;
Код:
thr= class(TThread)
  private
    FHandles: array[0..2] of THandle;
    FLock: TCriticalSection;
  
    fLogEvent: string;
    ...
    function GetLogEvent: string;
    procedure SetLogEvent(const Value: string);
    ...
  protected
  ...
    procedure AddLogEvent;
  public
...
  published

   ...
    property LogEvent: string read GetLogEvent write SetLogEvent;
   ...
  end;
Код:
procedure Thr.SetLogEvent(const Value: string);
begin
  FLock.Enter;
  try
    if Value <> fLogEvent then
    begin
      fLogEvent := Value;
      SetEvent(FHandles[2])
    end;

  finally
  Flock.leave;
  end;

Код:
constructor Thr.Create(...);
begin

  inherited Create(False);
  
  FHandles[0] := CreateEvent(nil, False, False, nil);
  // Управление завершением потока
  FHandles[1] := CreateEvent(nil, true, true, nil); // Управление паузой
  FHandles[2] := CreateEvent(nil, True, True, nil); // LogEvent
....
  SetEvent(FHandles[2]); //тестовый вызов, который не срабатывает
end;

Читал другие сайты, якобы нужно юзать WaitForSinglObject, но ведь WAIT_OBJECT_0 и WAIT_OBJECT_0+1 срабатывает?
и не уверен, что передавать нужно @FHandles[0] или @FHandles?
Ответить с цитированием
  #13  
Старый 21.04.2018, 14:14
Аватар для dr. F.I.N.
dr. F.I.N. dr. F.I.N. вне форума
I Like it!
 
Регистрация: 12.12.2009
Адрес: Россия, г. Новосибирск
Сообщения: 660
Версия Delphi: D6/D7
Репутация: 26643
По умолчанию

Решил, что проще будет написать пример
И еще, WaitForSinglObject - используется для проверки единичного события, а WaitForMultipleObjects - для нескольких (третий параметр означает True - "ждать всех событий", False - "ждать любое событие из...") А что касается @FHandles[0] или @FHandles, то тут такая ситуация:
Допустим у вас в массиве FHandles 5 хендлов событий и на текущей операции вы хотите отслеживать только с третьего, то передаете в качестве параметра ссылку на третий (не забудьте корректно указать количество отслеживаемых хендлов WaitForMultiplyObjects(3, @FHandles[2],...)). А если нужно отслеживать все, то указание @FHandles[0] или @FHandles равнозначно.
Вложения
Тип файла: zip Thread Test.zip (193.4 Кбайт, 4 просмотров)
__________________
Грамотно поставленный вопрос содержит не менее 50% ответа.
Грамотно поставленная речь вызывает уважение, а у некоторых даже зависть.

Последний раз редактировалось dr. F.I.N., 21.04.2018 в 14:20.
Ответить с цитированием
Этот пользователь сказал Спасибо dr. F.I.N. за это полезное сообщение:
nixon232 (21.04.2018)
  #14  
Старый 21.04.2018, 16:19
nixon232 nixon232 вне форума
Активный
 
Регистрация: 26.01.2014
Сообщения: 282
Версия Delphi: delphi xe4
Репутация: выкл
По умолчанию

Цитата:
Сообщение от dr. F.I.N.
Решил, что проще будет написать пример
И еще, WaitForSinglObject - используется для проверки единичного события, а WaitForMultipleObjects - для нескольких (третий параметр означает True - "ждать всех событий", False - "ждать любое событие из...") А что касается @FHandles[0] или @FHandles, то тут такая ситуация:
Допустим у вас в массиве FHandles 5 хендлов событий и на текущей операции вы хотите отслеживать только с третьего, то передаете в качестве параметра ссылку на третий (не забудьте корректно указать количество отслеживаемых хендлов WaitForMultiplyObjects(3, @FHandles[2],...)). А если нужно отслеживать все, то указание @FHandles[0] или @FHandles равнозначно.
Спасибо за потраченное время, как всегда кратко и четко.
Ответить с цитированием
Ответ


Delphi Sources

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

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 12:00.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter