Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Thread. Непонятно работает Suspend и Resume ...


Автор: Matematik 20.8.2007, 20:47
Turbo Delphi
Borland® Delphi® for Microsoft® Windows™ Version 10.0.2558.35231 Update 2

По кнопке 1 запускается 5 потоков, которые сразу засыпают suspend. Последний 5йы поток запоминается в переменную t
По кнопке 2 поток t.resume. В результате в memo1 должно записаться символ 5.
Так происходит без отладки.
Если поставить breakpoint на sleep(2000) и повторить действие выше, то запустятся все потоки и в мемо запишется
Код

5
1
3
2
4

Объясните, отладка глючит или я что-то не знаю?[/B]

Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  TMyThead = class(TThread)
  private
    { Private declarations }
  public
    Tag: String;
  protected
    procedure DoShow;
    procedure Execute; override;
  end;

var
  Form1: TForm1;
  t : TMyThead;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var j : Integer;
begin
  for j:=1 to 5 do
  begin
    t := TMyThead.Create(True);
    t.tag := IntToStr(j);
    t.Resume;
  end;
end;

{ TMyThead }

procedure TMyThead.DoShow;
begin
  Form1.Memo1.Lines.Add(Tag);
end;

procedure TMyThead.Execute;
begin
  while True do
  begin
    Suspend;
    Synchronize(DoShow);
    Sleep(2000); // тут breakpoint
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  t.Resume;
end;

end.

Автор: Mikh@il 20.8.2007, 21:15
Я так понял, тебе надо сделать чтобы потоки писали в memo 1,2,3,4,5
Если так, то используй обьекты синхронизации:

Ищи инфу про Mutex, Semafor, critical section

Автор: Matematik 20.8.2007, 21:41
Мне ничего не надо.
Код в отладке работает не так как без нее.
Проблема в том что делая Resum 1го потока, все остальные тоже запускаються

Автор: Snowy 20.8.2007, 21:44
Цитата
  for j:=1 to 5 do
  begin
    t := TMyThead.Create(True);
    t.tag := IntToStr(j);
    t.Resume;
  end;
Что-то я не вижу, где написано, что треды должны спать?
Все созданные треды сразу ресумятся.

Автор: Matematik 20.8.2007, 21:45
Snowy, В TMyThead.Execute засыпают

Автор: Mikh@il 20.8.2007, 21:51
У тя когда стоит breakpoin у тя Sleep не срабатывает, отсюда они все и запускаются

Автор: Matematik 20.8.2007, 22:02
Цитата(Mikh@il @  20.8.2007,  21:51 Найти цитируемый пост)
У тя когда стоит breakpoin у тя Sleep не срабатывает, отсюда они все и запускаются 

Не понимаю твою логику

Автор: MetalFan 20.8.2007, 22:14
мда... интересная ситуация... есть подозрение, что не стоит из кода в потоке себя самого усыплять

Автор: Matematik 20.8.2007, 22:15
MetalFan, пытался усыплять в синхронизации. Тоже самое

Автор: MetalFan 20.8.2007, 22:19
MSDN не рекомендует использовать усыпление потока для синхронизации...
Цитата(MSDN)
The SuspendThread function is not particularly useful for synchronization because it does not control the point in the code at which the thread's execution is suspended. However, you might want to suspend a thread in a situation where you are waiting for user input that could cancel the work the thread is performing. If the user input cancels the work, have the thread exit; otherwise, call ResumeThread.

Автор: Snowy 20.8.2007, 22:33
Не. Не тот кусочек. Вот этот интереснее.:
Цитата
If the function succeeds, execution of the specified thread is suspended and the thread's suspend count is incremented. Suspending a thread causes the thread to stop executing user-mode (application) code.
This function is primarily designed for use by debuggers. 

Автор: dumb 21.8.2007, 01:59
судя по всему, это глюк отладчика. вот только интересно - он "отпускает" потоки при срабатывании бряка или после продолжения выполнения(это более вероятный вариант)? - добавь вывод времени в мемо. возможно, он(отладчик) при "отпускании" смотрит на предмет нахождения eip(непосредственно или в call-stack'е) контекста замороженных потоков в пределах функции, где стоит бряк.
это так... догадки. нету у меня Turbo Delphi... smile

Автор: sentry 21.8.2007, 10:07
У меня есть Turbo Delphi, решил попробовать. Только я ставил breakpoint'ы в Button1Click. И вот результаты:
1) оказалось, что в зависимости от того, на какой строке стоит бряк, при нажатии на Button1 выводит: либо ничего, либо 1 2 3, либо 1 2 3 4;
2) ставлю бряк там, где 1 2 3 4, запускаю, нажимаю кнопку, попадаю на ту строку, жму F9, снова попадаю туда, снимаю бряк, жму F9 - вывело 1 (а не 1 2 3 4);
3) делаю аналогично там, где 1 2 3, только ничего не выводит.

Может, мне тоже кто-нибудь объяснит, что это такое?  smile 

Автор: Matematik 21.8.2007, 16:19
MetalFan, 
Snowy, 
Спасибо что направили в нужное направление. RTFM помогает.

Я так понял что сам отладчик delphi использует SuspendThread и ResumeThread при отладке кода.
Попробую подругому организовать паузу потока.


Автор: Felan 22.8.2007, 10:47
А чего ее делать? Делаешь Event и ручками пускаешь... типа такого (выдрано из проекта как есть)

Метод потока:
Код

procedure TiaParamsToRegMonitor.Execute;
begin
  SetName;

  while (not Terminated) do
  Begin
    try
      fStopEvent.WaitFor(INFINITE);

      If Terminated then Continue;

      if (GetTickCount() - fTimeCount) > ( fRefreshInterval ) then
        begin
          try
            Monitoring; //Функциональный метод потока
          finally
            fTimeCount := GetTickCount;
          end;
        end;

      //пауза что бы поток не кушал такты процессора слишком сильно
      Sleep(100);
    except
      on E: Exception do
        begin
          WriteToLog('Error in thread procedure <' + e.Message + '>');
        end;
    end;
  end;
end;



Создание класса:
Код

constructor TiaParamsToRegMonitor.Create(CreateSuspended: Boolean);
begin
  inherited;

  fCS_AccessToProps := TCriticalSection.Create;
  fStopEvent := TSimpleEvent.Create;
  fStopEvent.ResetEvent;
  setRefreshtInterval(DEF_REFRESH_INTERVAL);
  fRW := TiaRegistryWorker.Create(DEF_SKS_REGISTRY_ROOT, DEF_SKS_REGISTRY_SUBKEY, DEF_SKS_PROGRAM_SUBKEY);

  Priority := tpLowest;
  FreeOnTerminate := False;
end;



Методы пуска и остановки:
Код

procedure TiaParamsToRegMonitor.Start;
begin
  // Здесь может быть какая-нибудь инициализация
  Reset;
end;

procedure TiaParamsToRegMonitor.Stop;
begin
  fStopEvent.ResetEvent;

  setIsStarted( False );
end;



И надое еще не забыть метод аварийного выхода, если у тебя в методе старта потока будет какая-то инициализация. Т.к. для того. что бы корректно выйти из потока надо сначала установить Terminated, а потом отпустить его. Вот что бы без проблем отпустить, без инициализации в методе старт можно сделать так:
Код

procedure TiaParamsToRegMonitor.Reset;
begin
  fTimeCount :=  GetTickCount;
  fStopEvent.SetEvent;
  setIsStarted( True );
end;


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)