Проблема С Кодом. Помогите

Тема в разделе "Delphi - Компоненты", создана пользователем programmer8329, 28 июн 2012.

  1. programmer8329

    Регистрация:
    28 июн 2012
    Сообщения:
    19
    Симпатии:
    0
    Нашел следующую справку вроде все просто

    Waiting for a task to be completed

    Sometimes, you need to wait for a thread to finish some operation rather than
    waiting for a particular thread to complete execution. To do this, use an event object.
    Event objects (TEvent) should be created with global scope so that they can act like
    signals that are visible to all threads.
    When a thread completes an operation that other threads depend on, it calls
    TEvent.SetEvent. SetEvent turns on the signal, so any other thread that checks will
    know that the operation has completed. To turn off the signal, use the ResetEvent
    method.
    For example, consider a situation where you must wait for several threads to
    complete their execution rather than a single thread. Because you don’t know which
    thread will finish last, you can’t simply use the WaitFor method of one of the threads.
    Instead, you can have each thread increment a counter when it is finished, and have
    the last thread signal that they are all done by setting an event.


    The following code shows the end of the OnTerminate event handler for all of the
    threads that must complete. CounterGuard is a global critical section object that
    prevents multiple threads from using the counter at the same time. Counter is a global
    variable that counts the number of threads that have completed.

    procedure TDataModule.TaskThreadTerminate(Sender: TObject);
    begin
    ƒ
    CounterGuard.Acquire; { obtain a lock on the counter }
    Dec(Counter); { decrement the global counter variable }
    if Counter = 0 then
    Event1.SetEvent; { signal if this is the last thread }
    CounterGuard.Release; { release the lock on the counter }
    ƒ
    end;
    The main thread initializes the Counter variable, launches the task threads, and waits
    for the signal that they are all done by calling the WaitFor method. WaitFor waits for a
    specified time period for the signal to be set, and returns one of the values from Table

    The following shows how the main thread launches the task threads and then
    resumes when they have all completed:

    Event1.ResetEvent; { clear the event before launching the threads }
    for i := 1 to Counter do
    TaskThread.Create(False); { create and launch task threads }
    if Event1.WaitFor(20000) <> wrSignaled then
    raise Exception;
    { now continue with the main thread. All task threads have finished }



    Note If you do not want to stop waiting for an event after a specified time period, pass the
    WaitFor method a parameter value of INFINITE. Be careful when using INFINITE,
    because your thread will hang if the anticipated signal is never received.



    Это уже мой код

    unit Unit1;

    interface

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

    type
    TForm1 = class(TForm)
    Button1: TButton;
    CheckBox1: TCheckBox;
    CheckBox2: TCheckBox;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure DoWork1(Sender: TObject);
    procedure FormCreate(Sender: TObject);

    private
    { Private declarations }
    public
    { Public declarations }
    end;
    TMyThread1 = class(TThread)
    private
    { Private declarations }
    protected
    procedure DoWork;
    procedure Execute; override;
    end;

    TMyThread2 = class(TThread)
    private
    { Private declarations }
    protected
    procedure DoWork;

    procedure Execute; override;
    end;

    var
    Form1: TForm1;
    T1 : TMyThread1;
    T2 : TMyThread2;
    event:tevent;
    Counter:integer;
    CounterGuard:TCriticalSection;
    implementation

    {$R *.dfm}
    procedure TMyThread1.Execute;
    begin

    Synchronize(DoWork);
    end;

    procedure TMyThread2.Execute;
    begin
    Synchronize(DoWork);
    end;

    procedure TMyThread1.DoWork;

    begin
    Form1.CheckBox1.Checked := false;

    end;

    procedure TMyThread2.DoWork;
    begin
    Form1.CheckBox1.Checked := false;

    end;

    procedure Tform1.DoWork1(Sender: TObject);
    begin


    CounterGuard.Acquire; { obtain a lock on the counter }
    Dec(Counter); { decrement the global counter variable }
    if Counter = 0 then
    event.SetEvent; { signal if this is the last thread }
    CounterGuard.Release; { release the lock on the counter }

    end;
    procedure TForm1.Button1Click(Sender: TObject);
    begin


    Event.ResetEvent;
    T2 := TMyThread2.Create(False);
    T1 := TMyThread1.Create(False);
    T2.OnTerminate:=DoWork1;
    T1.OnTerminate:=DoWork1;



    if event.WaitFor(infinite)=wrSignaled then
    showmessage('done');


    Button1.Caption := 'Stop';

    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    event:=tevent.Create(nil,true,true,'');

    Counter:=2;
    end;

    initialization

    CounterGuard:=Tcriticalsection.Create;
    end.


    Но этот код не работает. я что нибудь сделал не так?. Помогите. Он не сигналит когда потоки прекращают работать
     
  2. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Что значит "не сигналит"?
    Вы можете объяснить человеческим языком, что Вы ожидаете от программы (как Вам кажется, что должно происходить?) в процессе выполнения кода который Вы изложили?
     
  3. programmer8329

    Регистрация:
    28 июн 2012
    Сообщения:
    19
    Симпатии:
    0
    Но все же ясно, после того как два потока завершают работу они устанавливают событие в dowork1, которое должно уловить waitfor в главном потоке т.е в коде кнопки после чего появляется сообщение "done" но этого не происходит. Что не так ?
     
  4. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Ясно как раз, что Вы не прочитали справку по TThread.
    Код (Delphi):
    {1} T1 := TMyThread1.Create(False);
    //...
    {2} T1.OnTerminate:=DoWork1;
    Сточка {1} говорит о том что нить должна стартовать сразу же (после завершения конструктора Create).
    Т.е. можете быть уверены, что к моменту строчки {2} Ваша нить уже отработала... :(
    Если Вы хотите "успеть" назначить обработчик OnTerminate, то сначала его надо назначить а уж потом стартовать нить...
    Код (Delphi):
     T1 := TMyThread1.Create(True);
    T1.OnTerminate := DoWork1;
    T1.Resume;
    Но мне все равно, извините, не понятен смысл Вашего кода...
    Ведь DoWork1 все равно будет выполняться в главном потоке (после того как нити отработают)...
     
  5. programmer8329

    Регистрация:
    28 июн 2012
    Сообщения:
    19
    Симпатии:
    0
    Dowork1 вызывается из моего кода правильно, я проверял, вы тоже можете проверить вставьте showmessage в dowork1 и вы увидите что его вызывают два раза. И событие тоже устанавливается но почемуто waitfor не видит его. А от того главный это поток или нет суть не меняется, все сообщение не выходит.
     
  6. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Еще раз Вам повторяю... DoWork1 должен выполняться (исходя из вышего кода) в ОСНОВНОМ ПОТОКЕ!
    Но он (основной поток) не может этого сделать, потому как "висит" на ожидании Вашего Event.WaitFor(infinite)...
    Разве не очевидно? :)
    Поэтому в коде Вашем смысла я не углядел...
    Либо Вынесите Event.WaitFor(infinite)... в отдельную нить, либо DoWork1 выполняйте непосредственно в теле (T1, T2).
    Если Вам нужно чтобы Dec(Counter); происходил по завершении нити, включите код из DoWork1 в конец тела Execute, либо переопределите сам DoTerminate (как Вы сделали с методом Execute).
     
  7. programmer8329

    Регистрация:
    28 июн 2012
    Сообщения:
    19
    Симпатии:
    0
    Я попробовал сделать как вы мне сказали но все равно не выходит. Может вы перепишите мой код и выложите правильный вариант, там всего несколько строк, а я протестирую,ведь задача вполне обычная, как узнать что потоки завершили работу не напрягая ресурсы системы, я уверен любой серьезный программист сталкивался с подобный проблемой.
     
  8. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Это называется "пойди туда, не знаю куда"... :blink:
    Скажите, как можно исправить то, смысл чего не понимаешь?
    Вы же так и не рассказали, чего Вы добиваетесь от своего кода (алгоритм работы)...

    Ок, раз я сегодня "дежурный экстрасенс", осмелюсь предположить что Вы хотели что нибуть типа этого
    Код (Delphi):
    unit Unit1;

    interface

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

    type
    TMainThread = class(TThread)
    protected
    procedure Execute; override;
    public
    StopMSG : string;
    MSGWindow: HWND;
    end;

    TMyThread1 = class(TThread)
    protected
    procedure DoTerminate; override;
    procedure DoWork;
    procedure Execute; override;
    end;

    TMyThread2 = class(TThread)
    protected
    procedure DoTerminate; override;
    procedure DoWork;
    procedure Execute; override;
    end;

    type
    TForm1 = class(TForm)
    Button1: TButton;
    CheckBox1: TCheckBox;
    CheckBox2: TCheckBox;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    private
    { Private declarations }
    public
    procedure ResetButton(Sender: TObject);
    { Public declarations }
    end;


    var
    Form1: TForm1;

    { Рабочий поток (нить) 1 }
    T1 : TMyThread1;
    { Рабочий поток (нить) 2 }
    T2 : TMyThread2;

    { Поток (нить) запускающий нити 1,2
    и ожидающий событие Event }

    MainThread : TMainThread;

    { Событие, которое установит на DoTerminate одна из рабочих нитей
    либо пользователь (кнопкой Stop, если ему надоест ждать) }

    Event: TEvent;

    { Счетчик, который декрементят рабочие нити }
    Counter:integer;

    { Критическая секция, не дающая рабочим нитям "драться" }
    CounterGuard: TCriticalSection;

    implementation

    {$R *.dfm}


    { TMyThread1 }

    procedure TMyThread1.DoWork;
    begin
    Form1.CheckBox1.Checked := not Form1.CheckBox1.Checked;
    Form1.Caption := Format('Counter = %d (Поток %s)',[Counter,Self.ClassName]);
    Form1.Refresh;
    end;

    procedure TMyThread1.Execute;
    begin
    { Крутимся в цикле, пока счетчик не обнулится или нас не "терминируют" }
    while (not Terminated) do
    begin
    CounterGuard.Acquire; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
    Sleep(100);
    Synchronize(DoWork);
    Dec(Counter);
    CounterGuard.Release; // Заняли секцию. Пока мы в ней, "никто другой не войдет"

    if (Counter < 1 ) then
    Break;
    end;
    end;

    procedure TMyThread1.DoTerminate;
    begin
    CounterGuard.Acquire; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
    if (Counter < 1) then // Если счетчик обнулился, "рождаем событие"
    Event.SetEvent;
    CounterGuard.Release; // Освободили секцию.
    inherited;
    end;


    { TMyThread2 }

    procedure TMyThread2.DoWork;
    begin
    Form1.CheckBox2.Checked := not Form1.CheckBox2.Checked;
    Form1.Caption := Format('Counter = %d (Поток %s)',[Counter,Self.ClassName]);
    Form1.Refresh;
    end;

    procedure TMyThread2.Execute;
    begin
    { Крутимся в цикле, пока счетчик не обнулится или нас не "терминируют" }
    while (not Terminated) do
    begin
    CounterGuard.Acquire; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
    Sleep(100);
    Synchronize(DoWork);
    Dec(Counter);
    CounterGuard.Release; // Заняли секцию. Пока мы в ней, "никто другой не войдет"

    if (Counter < 1 ) then
    Break;
    end;
    end;

    procedure TMyThread2.DoTerminate;
    begin
    CounterGuard.Acquire; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
    if (Counter < 1) then // Если счетчик обнулился, "рождаем событие"
    Event.SetEvent;
    CounterGuard.Release; // Освободили секцию.
    inherited;
    end;


    { TMainThread }

    procedure TMainThread.Execute;
    begin
    // Запустили рабочие нити
    T1.Resume;
    T2.Resume;

    // Ожидаем рождения события.
    // !!!! Внимание !!! Управление в поток вернется ТОЛЬКО после получения результата WaitFor !!!
    // А до тех пор, этот поток (нить) будет находитьс в "записшем" состоянии

    if (Event.WaitFor(INFINITE) <> wrSignaled) then // События не дожналить
    MessageBox(0, 'Ошибка!', PChar(Application.Title), MB_OK + MB_ICONSTOP +
    MB_TOPMOST)
    else // Событие родилось
    MessageBox(MSGWindow, PChar(StopMSG), PChar(Application.Title), MB_OK +
    MB_ICONINFORMATION + MB_TOPMOST);
    end;

    { TForm1 }

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    // Рождение критической секции
    CounterGuard := Tcriticalsection.Create;

    // Рождение экземпляра TEvent
    Event := TEvent.Create(nil,true,true,'');
    ResetButton(Self);
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    if (Button1.Caption = 'Stop') then // Остановка вручную (если нам надоело ждать)
    begin
    // Останавливаем рабочие нити
    T1.Terminate;
    T2.Terminate;

    // Ждем их фактической остановки
    T1.WaitFor;
    T2.WaitFor;

    MainThread.StopMSG := 'Остановлено пользователем';

    // Вручную устанавливаем событие
    Event.SetEvent;

    // Ждем завершения MainThread
    MainThread.WaitFor;

    // Освобождаем память
    MainThread.Free;
    T1.Free;
    T2.Free;
    end
    else                     // Запуск "системы"
    begin
    // Устанавливаем счетчик
    Counter := 100;
    // Сбрасываем (тушим) событие
    Event.ResetEvent;

    // Рождаем рабочие нити
    T2 := TMyThread2.Create(True);
    T1 := TMyThread1.Create(True);

    // Рождаем поток - ловец события
    MainThread := TMainThread.Create(True);
    MainThread.StopMSG := 'Готово!'#13+'Сигнал получен!';
    MainThread.MSGWindow := Form1.Handle;
    MainThread.OnTerminate := ResetButton;

    // Запускаем "Систему"
    MainThread.Resume;

    Button1.Caption := 'Stop';
    end;

    end;


    procedure TForm1.ResetButton(Sender: TObject);
    begin
    Caption := 'Готов к работе';
    Button1.Caption := 'Start';
    end;

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
    Event.Free;
    CounterGuard.Free;
    end;

    end.
    Ну и тогда уж, вот Вам исходники:
    Посмотреть вложение ThreadTest.rar
     
  9. programmer8329

    Регистрация:
    28 июн 2012
    Сообщения:
    19
    Симпатии:
    0
    Браво я протестировал ваш пример, все работает, я например обращался на западные форумы , например вот здесь http://codeby.net/forum/threads/47530.html, но никто помочь мне не смог
    Похоже на этом форуме настоящие программисты.
    Я упростил ваш пример и все работает но вот почему сообщения ”Yes, it works”
    которое вызывается после завершения потоков, почему выходит то в нормальной форме, то в слишком большом виде, а почему так происходит не понятно.

    unit Unit1;

    interface

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

    type
    TMainThread = class(TThread)
    protected
    procedure Execute; override;
    public

    end;

    TMyThread1 = class(TThread)
    protected
    procedure DoTerminate; override;
    procedure DoWork;
    procedure Execute; override;
    end;

    TMyThread2 = class(TThread)
    protected
    procedure DoTerminate; override;
    procedure DoWork;
    procedure Execute; override;
    end;

    type
    TForm1 = class(TForm)
    Button1: TButton;
    CheckBox1: TCheckBox;
    CheckBox2: TCheckBox;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    private
    { Private declarations }
    public
    procedure ResetButton(Sender: TObject);
    { Public declarations }
    end;


    var
    Form1: TForm1;

    T1 : TMyThread1;
    T2 : TMyThread2;

    MainThread : TMainThread;

    Event: TEvent;


    Counter:integer;

    CounterGuard: TCriticalSection;

    implementation

    {$R *.dfm}


    { TMyThread1 }

    procedure TMyThread1.DoWork;
    begin


    end;

    procedure TMyThread1.Execute;
    begin
    { some code here }

    end;

    procedure TMyThread1.DoTerminate;
    begin

    CounterGuard.Acquire;
    Dec(Counter);
    if (Counter = 0) then
    Event.SetEvent;


    CounterGuard.Release;
    inherited;
    end;




    procedure TMyThread2.DoWork;
    begin


    end;

    procedure TMyThread2.Execute;
    begin
    { some code here }

    end;

    procedure TMyThread2.DoTerminate;
    begin

    CounterGuard.Acquire;
    Dec(Counter);
    if (Counter = 0) then
    Event.SetEvent;


    CounterGuard.Release;
    inherited;
    end;


    { TMainThread }

    procedure TMainThread.Execute;
    begin

    T1.Resume;
    T2.Resume;



    if (Event.WaitFor(INFINITE) = wrSignaled) then
    showmessage('Yes, it works');
    end;

    { TForm1 }

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    CounterGuard := Tcriticalsection.Create;

    Event := TEvent.Create(nil,true,true,'');
    counter:=2;
    ResetButton(Self);
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    begin
    if (Button1.Caption = 'Stop') then
    begin

    T1.Terminate;
    T2.Terminate;


    MainThread.Free;
    T1.Free;
    T2.Free;
    end
    else
    begin

    Event.ResetEvent;


    T2 := TMyThread2.Create(True);
    T1 := TMyThread1.Create(True);


    MainThread := TMainThread.Create(True);

    MainThread.OnTerminate := ResetButton;


    MainThread.Resume;

    Button1.Caption := 'Stop';
    end;

    end;


    procedure TForm1.ResetButton(Sender: TObject);
    begin
    Caption := 'Готов к работе';
    Button1.Caption := 'Start';

    end;

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
    Event.Free;
    CounterGuard.Free;
    end;

    end.
     
  10. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Не вижу причин, почему это не должно было работать...
    Советую научиться пользоваться кнопочкой F1...
    Если вы почитаете справку, то узнаете, что ShowMessage это диалог который "растёт" от TApplication, который в свою очередь есть главный поток. А всё что связано с формами главного потока, в параллельных нитях следует выполнять через Synchronize. Иначе... ну результат Вы видели... :blink:
    Если Вы обратили внимание, для вывода сообщений в параллельных нитях, я использовал MessageBox... который есть WinAPI...
    Большая просьба, когда постите код, включайте его пожалуйста в мнемотэг code... это такая кнопочка с надписью PAS над окошком поста (4-я справа)... :)
    А то очень уж тяжело читать
    Спасибо за понимание...

    PS.
    Да... вот еще что... Я тут посмотрел еще раз Ваш измененный код...
    У меня есть некоторые замечания...
    1. Вот эти строчки
    Код (Delphi):
    T1.Terminate;
    T2.Terminate;
    вовсе не означают, что T1 и T2 тут же умрут. Метод Terminate всего лишь выставляют приватное поле нити FTerminated в состояние True
    Отсюда следует:
    а). После T2.Terminate; обязательно должна стоять строчка T1.WaitFor; иначе может получиться... не то что хотелось бы.
    б). Параллельная нить должна сама проверять "не пора ли ей умереть"... Для этого внутри Вашего { some code here } , причем (если это не цикл коротких операций) во многих местах.

    2. MainThread.Free; до того как поток терминирован - плохая идея... Имейте в виду - Эта команда разрушит Экземпляр класса TMainThread но вовсе не саму нить... :)
    Я даже боюсь гадать, что может произойти, когда ничего не подозревающая (о кончине класса-обертки) нить, после штатного (как ей самой кажется) завершения, попытается задейтвовать области памяти, которые Вы так необдуманно освободили деструктором MainThread...
     
  11. programmer8329

    Регистрация:
    28 июн 2012
    Сообщения:
    19
    Симпатии:
    0
    // Запускаем "Систему"
    MainThread.Resume;
    // В вашем примере как заставить поток остановиться и дождаться завершения MainThread //а потом уже устанавливать свойство СТОП в названия кнопки. Т.Е задача такая основной //поток запускает 15 потоков и ждет завершения всех 15 поток а потом продолжает //работать или проще как заставить поток остановитья на этом самом месте и дождавшись //завершения майнсреда установить капшн СТОП
    Button1.Caption := 'Stop';
     
  12. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Код (Delphi):
    procedure TMainThread.DisableButton;
    begin
      FStopButton.Caption := 'Wait...';
      FStopButton.Enabled := False;
    end;
     
    procedure TMainThread.EnableButton;
    begin
      FStopButton.Caption := 'Stop';
      FStopButton.Enabled := True;
    end;
     
    procedure TMainThread.Execute;
    var
    isDone: Boolean;
    begin
      Synchronize(DisableButton);
      ChildThread1.Resume;
      ChildThread2.Resume;
    //  ChildThread3.Resume;
    // ...
      ChildThread14.Resume;
      ChildThread15.Resume;
     
      isDone := ChildThread1.Terminated and ChildThread2.Terminated and
                // ChildThread3.Terminated and ChildThread4.Terminated and
                // ...
                ChildThread14.Terminated and ChildThread15.Terminated;
     
      while not isDone do begin
        Sleep(20);
      isDone := ChildThread1.Terminated and ChildThread2.Terminated and
                // ChildThread3.Terminated and ChildThread4.Terminated and
                // ...
                ChildThread14.Terminated and ChildThread15.Terminated;
     
      end;
     
      Synchronize(EnableButton);
      // bla bla
    end;
     
     
  13. programmer8329

    Регистрация:
    28 июн 2012
    Сообщения:
    19
    Симпатии:
    0
    Здравствуйте вы не отстанавливайте поток в основном коде (коде кнопки), кнопка по прежнему получает капш стоп в тот самый момент пока работают дочерние потоки, вы изменяете капшн из дочених потоков, а у меня задача совсем другая предположим кнопка вызавает дочерние потоки а после MainThread.Resume; у меня продолжается код который продолжает испольняться во время работы дочерниех потоков не дождавшись из завершения, а мне нужно чтоб код после MainThread.Resume; испольнялся после завершения дочерних потоков. Пример
    Код (Delphi):
    unit Unit1;
     
    interface
     
    uses
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    Dialogs, SyncObjs, StdCtrls;
     
    type
    TMainThread = class(TThread)
    protected
    procedure Execute; override;
    public
    StopMSG : string;
    MSGWindow: HWND;
    end;
     
    TMyThread1 = class(TThread)
    protected
    procedure DoTerminate; override;
    procedure DoWork;
    procedure Execute; override;
    end;
     
    TMyThread2 = class(TThread)
    protected
    procedure DoTerminate; override;
    procedure DoWork;
    procedure Execute; override;
    end;
     
    type
    TForm1 = class(TForm)
    Button1: TButton;
    CheckBox1: TCheckBox;
    CheckBox2: TCheckBox;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    private
    { Private declarations }
    public
    procedure ResetButton(Sender: TObject);
    { Public declarations }
    end;
     
     
    var
    Form1: TForm1;
     
    { Рабочий поток (нить) 1 }
    T1 : TMyThread1;
    { Рабочий поток (нить) 2 }
    T2 : TMyThread2;
     
    { Поток (нить) запускающий нити 1,2
    и ожидающий событие Event }

    MainThread : TMainThread;
     
    { Событие, которое установит на DoTerminate одна из рабочих нитей
    либо пользователь (кнопкой Stop, если ему надоест ждать) }

    Event: TEvent;
     
    { Счетчик, который декрементят рабочие нити }
    Counter:integer;
     
    { Критическая секция, не дающая рабочим нитям "драться" }
    CounterGuard: TCriticalSection;
     
    implementation
     
    {$R *.dfm}
     
     
    { TMyThread1 }
     
    procedure TMyThread1.DoWork;
    begin
    Form1.CheckBox1.Checked := not Form1.CheckBox1.Checked;
    Form1.Caption := Format('Counter = %d (Поток %s)',[Counter,Self.ClassName]);
    Form1.Refresh;
    end;
     
    procedure TMyThread1.Execute;
    begin
    { Крутимся в цикле, пока счетчик не обнулится или нас не "терминируют" }
    while (not Terminated) do
    begin
    CounterGuard.Acquire; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
    Sleep(100);
    Synchronize(DoWork);
    Dec(Counter);
    CounterGuard.Release; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
     
    if (Counter < 1 ) then
    Break;
    end;
    end;
     
    procedure TMyThread1.DoTerminate;
    begin
    CounterGuard.Acquire; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
    if (Counter < 1) then // Если счетчик обнулился, "рождаем событие"
    Event.SetEvent;
    CounterGuard.Release; // Освободили секцию.
    inherited;
    end;
     
     
    { TMyThread2 }
     
    procedure TMyThread2.DoWork;
    begin
    Form1.CheckBox2.Checked := not Form1.CheckBox2.Checked;
    Form1.Caption := Format('Counter = %d (Поток %s)',[Counter,Self.ClassName]);
    Form1.Refresh;
    end;
     
    procedure TMyThread2.Execute;
    begin
    { Крутимся в цикле, пока счетчик не обнулится или нас не "терминируют" }
    while (not Terminated) do
    begin
    CounterGuard.Acquire; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
    Sleep(100);
    Synchronize(DoWork);
    Dec(Counter);
    CounterGuard.Release; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
     
    if (Counter < 1 ) then
    Break;
    end;
    end;
     
    procedure TMyThread2.DoTerminate;
    begin
    CounterGuard.Acquire; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
    if (Counter < 1) then // Если счетчик обнулился, "рождаем событие"
    Event.SetEvent;
    CounterGuard.Release; // Освободили секцию.
    inherited;
    end;
     
     
    { TMainThread }
     
    procedure TMainThread.Execute;
    begin
    // Запустили рабочие нити
    T1.Resume;
    T2.Resume;
     
    // Ожидаем рождения события.
    // !!!! Внимание !!! Управление в поток вернется ТОЛЬКО после получения результата WaitFor !!!
    // А до тех пор, этот поток (нить) будет находитьс в "записшем" состоянии
     
    if (Event.WaitFor(INFINITE) <> wrSignaled) then // События не дожналить
    MessageBox(0, 'Ошибка!', PChar(Application.Title), MB_OK + MB_ICONSTOP +
    MB_TOPMOST)
    else // Событие родилось
    MessageBox(MSGWindow, PChar(StopMSG), PChar(Application.Title), MB_OK +
    MB_ICONINFORMATION + MB_TOPMOST);
    end;
     
    { TForm1 }
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
    // Рождение критической секции
    CounterGuard := Tcriticalsection.Create;
     
    // Рождение экземпляра TEvent
    Event := TEvent.Create(nil,true,true,'');
    ResetButton(Self);
    end;
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
    if (Button1.Caption = 'Stop') then // Остановка вручную (если нам надоело ждать)
    begin
    // Останавливаем рабочие нити
    T1.Terminate;
    T2.Terminate;
     
    // Ждем их фактической остановки
    T1.WaitFor;
    T2.WaitFor;
     
    MainThread.StopMSG := 'Остановлено пользователем';
     
    // Вручную устанавливаем событие
    Event.SetEvent;
     
    // Ждем завершения MainThread
    MainThread.WaitFor;
     
    // Освобождаем память
    MainThread.Free;
    T1.Free;
    T2.Free;
    end
    else                     // Запуск "системы"
    begin
    // Устанавливаем счетчик
    Counter := 100;
    // Сбрасываем (тушим) событие
    Event.ResetEvent;
     
    // Рождаем рабочие нити
    T2 := TMyThread2.Create(True);
    T1 := TMyThread1.Create(True);
     
    // Рождаем поток - ловец события
    MainThread := TMainThread.Create(True);
    MainThread.StopMSG := 'Готово!'#13+'Сигнал получен!';
    MainThread.MSGWindow := Form1.Handle;
    MainThread.OnTerminate := ResetButton;
     
    // Запускаем "Систему"
    MainThread.Resume;
     Button1.Caption := 'Stop';
    showmessage('Main thread finished its work');
    //сделайте пожалуйста так чтоб это сообщения вызывалось после "сигнал получен"
    end;
     
    end;
     
     
    procedure TForm1.ResetButton(Sender: TObject);
    begin
    Caption := 'Готов к работе';
    Button1.Caption := 'Start';
    end;
     
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
    Event.Free;
    CounterGuard.Free;
    end;
     
    end.
    Посмотрите на шоумессадж после MainThread.Resume; Сделайте так чтоб исходя из вашего примера сначала завершил работу Mainthread а потом вызывалось шоумессадж. я пробовал WaitForSingleObject, но он не сработал можно побровать использовать таймер который будет проверять значения boolean который станет true когда получет сигнал но это както не изящно.
    [DOUBLEPOST=1450008304,1450008293][/DOUBLEPOST]Здравствуйте вы не отстанавливайте поток в основном коде (коде кнопки), кнопка по прежнему получает капш стоп в тот самый момент пока работают дочерние потоки, вы изменяете капшн из дочених потоков, а у меня задача совсем другая предположим кнопка вызавает дочерние потоки а после MainThread.Resume; у меня продолжается код который продолжает испольняться во время работы дочерниех потоков не дождавшись из завершения, а мне нужно чтоб код после MainThread.Resume; испольнялся после завершения дочерних потоков. Пример
    Код (Delphi):
    unit Unit1;
     
    interface
     
    uses
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    Dialogs, SyncObjs, StdCtrls;
     
    type
    TMainThread = class(TThread)
    protected
    procedure Execute; override;
    public
    StopMSG : string;
    MSGWindow: HWND;
    end;
     
    TMyThread1 = class(TThread)
    protected
    procedure DoTerminate; override;
    procedure DoWork;
    procedure Execute; override;
    end;
     
    TMyThread2 = class(TThread)
    protected
    procedure DoTerminate; override;
    procedure DoWork;
    procedure Execute; override;
    end;
     
    type
    TForm1 = class(TForm)
    Button1: TButton;
    CheckBox1: TCheckBox;
    CheckBox2: TCheckBox;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    private
    { Private declarations }
    public
    procedure ResetButton(Sender: TObject);
    { Public declarations }
    end;
     
     
    var
    Form1: TForm1;
     
    { Рабочий поток (нить) 1 }
    T1 : TMyThread1;
    { Рабочий поток (нить) 2 }
    T2 : TMyThread2;
     
    { Поток (нить) запускающий нити 1,2
    и ожидающий событие Event }

    MainThread : TMainThread;
     
    { Событие, которое установит на DoTerminate одна из рабочих нитей
    либо пользователь (кнопкой Stop, если ему надоест ждать) }

    Event: TEvent;
     
    { Счетчик, который декрементят рабочие нити }
    Counter:integer;
     
    { Критическая секция, не дающая рабочим нитям "драться" }
    CounterGuard: TCriticalSection;
     
    implementation
     
    {$R *.dfm}
     
     
    { TMyThread1 }
     
    procedure TMyThread1.DoWork;
    begin
    Form1.CheckBox1.Checked := not Form1.CheckBox1.Checked;
    Form1.Caption := Format('Counter = %d (Поток %s)',[Counter,Self.ClassName]);
    Form1.Refresh;
    end;
     
    procedure TMyThread1.Execute;
    begin
    { Крутимся в цикле, пока счетчик не обнулится или нас не "терминируют" }
    while (not Terminated) do
    begin
    CounterGuard.Acquire; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
    Sleep(100);
    Synchronize(DoWork);
    Dec(Counter);
    CounterGuard.Release; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
     
    if (Counter < 1 ) then
    Break;
    end;
    end;
     
    procedure TMyThread1.DoTerminate;
    begin
    CounterGuard.Acquire; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
    if (Counter < 1) then // Если счетчик обнулился, "рождаем событие"
    Event.SetEvent;
    CounterGuard.Release; // Освободили секцию.
    inherited;
    end;
     
     
    { TMyThread2 }
     
    procedure TMyThread2.DoWork;
    begin
    Form1.CheckBox2.Checked := not Form1.CheckBox2.Checked;
    Form1.Caption := Format('Counter = %d (Поток %s)',[Counter,Self.ClassName]);
    Form1.Refresh;
    end;
     
    procedure TMyThread2.Execute;
    begin
    { Крутимся в цикле, пока счетчик не обнулится или нас не "терминируют" }
    while (not Terminated) do
    begin
    CounterGuard.Acquire; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
    Sleep(100);
    Synchronize(DoWork);
    Dec(Counter);
    CounterGuard.Release; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
     
    if (Counter < 1 ) then
    Break;
    end;
    end;
     
    procedure TMyThread2.DoTerminate;
    begin
    CounterGuard.Acquire; // Заняли секцию. Пока мы в ней, "никто другой не войдет"
    if (Counter < 1) then // Если счетчик обнулился, "рождаем событие"
    Event.SetEvent;
    CounterGuard.Release; // Освободили секцию.
    inherited;
    end;
     
     
    { TMainThread }
     
    procedure TMainThread.Execute;
    begin
    // Запустили рабочие нити
    T1.Resume;
    T2.Resume;
     
    // Ожидаем рождения события.
    // !!!! Внимание !!! Управление в поток вернется ТОЛЬКО после получения результата WaitFor !!!
    // А до тех пор, этот поток (нить) будет находитьс в "записшем" состоянии
     
    if (Event.WaitFor(INFINITE) <> wrSignaled) then // События не дожналить
    MessageBox(0, 'Ошибка!', PChar(Application.Title), MB_OK + MB_ICONSTOP +
    MB_TOPMOST)
    else // Событие родилось
    MessageBox(MSGWindow, PChar(StopMSG), PChar(Application.Title), MB_OK +
    MB_ICONINFORMATION + MB_TOPMOST);
    end;
     
    { TForm1 }
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
    // Рождение критической секции
    CounterGuard := Tcriticalsection.Create;
     
    // Рождение экземпляра TEvent
    Event := TEvent.Create(nil,true,true,'');
    ResetButton(Self);
    end;
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
    if (Button1.Caption = 'Stop') then // Остановка вручную (если нам надоело ждать)
    begin
    // Останавливаем рабочие нити
    T1.Terminate;
    T2.Terminate;
     
    // Ждем их фактической остановки
    T1.WaitFor;
    T2.WaitFor;
     
    MainThread.StopMSG := 'Остановлено пользователем';
     
    // Вручную устанавливаем событие
    Event.SetEvent;
     
    // Ждем завершения MainThread
    MainThread.WaitFor;
     
    // Освобождаем память
    MainThread.Free;
    T1.Free;
    T2.Free;
    end
    else                     // Запуск "системы"
    begin
    // Устанавливаем счетчик
    Counter := 100;
    // Сбрасываем (тушим) событие
    Event.ResetEvent;
     
    // Рождаем рабочие нити
    T2 := TMyThread2.Create(True);
    T1 := TMyThread1.Create(True);
     
    // Рождаем поток - ловец события
    MainThread := TMainThread.Create(True);
    MainThread.StopMSG := 'Готово!'#13+'Сигнал получен!';
    MainThread.MSGWindow := Form1.Handle;
    MainThread.OnTerminate := ResetButton;
     
    // Запускаем "Систему"
    MainThread.Resume;
     Button1.Caption := 'Stop';
    showmessage('Main thread finished its work');
    //сделайте пожалуйста так чтоб это сообщения вызывалось после "сигнал получен"
    end;
     
    end;
     
     
    procedure TForm1.ResetButton(Sender: TObject);
    begin
    Caption := 'Готов к работе';
    Button1.Caption := 'Start';
    end;
     
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
    Event.Free;
    CounterGuard.Free;
    end;
     
    end.
    Посмотрите на шоумессадж после MainThread.Resume; Сделайте так чтоб исходя из вашего примера сначала завершил работу Mainthread а потом вызывалось шоумессадж. я пробовал WaitForSingleObject, но он не сработал можно побровать использовать таймер который будет проверять значения boolean который станет true когда получет сигнал но это както не изящно.
     
Загрузка...
Похожие Темы - Проблема Кодом Помогите
  1. programmer8329
    Ответов:
    0
    Просмотров:
    1.733
  2. Renat11111
    Ответов:
    5
    Просмотров:
    3.140
  3. Zloikaktus
    Ответов:
    0
    Просмотров:
    12
  4. c0de3r
    Ответов:
    5
    Просмотров:
    134
  5. DobermannTT
    Ответов:
    10
    Просмотров:
    139

Поделиться этой страницей