26. Pou₧φvßnφ vlßken II
  1. Kdy₧ ji₧ mßme implementovßny t°φdy vlßken metodou Execute, m∙₧eme je pou₧φt v naÜφ aplikaci spuÜt∞nφm k≤du v metod∞ Execute. K pou₧itφ vlßkna, nejprve vytvo°φme instanci t°φdy vlßkna. Instanci vlßkna m∙₧eme vytvo°it tak, ₧e je spuÜt∞no bezprost°edn∞ nebo jej vytvo°φme v klidovΘm stavu, kterΘ pozd∞ji spustφme volßnφm metody Resume. Pro vytvo°enφ vlßkna s bezprost°ednφm spuÜt∞nφm p°edßme konstruktoru parametr false. Nap°. nßsledujφcφ °ßdek vytvß°φ vlßkno a spouÜtφ jeho provßd∞nφ:

  2. TMyThread *SecondProcess = new TMyThread(false); // vytvo°enφ a spuÜt∞nφ
    Nevytvß°ejte ve svΘ aplikaci mnoho vlßken. DoporuΦen² limit je 16 vlßken na proces v jednoprocesorovΘm systΘmu. Tento limit p°edpoklßdß, ₧e v∞tÜina t∞chto vlßken bude Φekat na externφ udßlosti. Pokud vÜechna vlßkna jsou aktivnφ, pak jich je mo₧no pou₧φt mΘn∞.
    M∙₧eme vytvo°it vφce instancφ stejnΘho typu vlßkna pro provßd∞nφ paralelnφho k≤du. Nap°. m∙₧eme vytvo°it novou instanci vlßkna v reakci na n∞jakou akci u₧ivatele umo₧≥ujφcφ ka₧dΘmu vlßknu zpracovßvat oΦekßvanou reakci.
    Mno₧stvφ Φasu CPU v∞novanΘ vlßknu je urΦeno nastavenφm priority v konstruktoru. M∙₧eme takΘ vytvo°it vlßkno v klidovΘm stavu a nastavit prioritu a₧ p°ed jeho spuÜt∞nφm:
    TMyThread *SecondProcess = new TMyThread(true);// vytvo°enφ bez spuÜt∞nφ
    SecondProcess->Priority = tpLower; // nastavenφ priority
    SecondProcess->Resume();           // spuÜt∞nφ vlßkna
    Vlßkna mohou b²t spouÜt∞na a zastavovßna n∞kolikrßt p°ed dokonΦenφm provßd∞nφ. Zastavenφ vlßkna je doΦasnΘ a provedeme jej volßnφm metody Suspend. Pro op∞tovnΘ spuÜt∞nφ volßme jeho metodu Resume. Suspend inkrementuje internφ ΦφtaΦ, a tak m∙₧eme vno°ovat volßnφ Suspend a Resume. Vlßkno nepokraΦuje v provßd∞nφ dokud vÜechny Suspend nemajφ odpovφdajφcφ Resume.
    K trvalΘmu ukonΦenφ vlßkna volßme metodu Terminate. Tato metoda nastavuje vlastnost Terminated vlßkna na true. Pokud metoda Execute je sprßvn∞ implementovßna, je periodicky testovßna vlastnost Terminated a ukonΦuje provßd∞nφ, kdy₧ je true.
    Kdy₧ naÜe aplikace vy₧aduje vφce instancφ stejnΘ t°φdy vlßkna (pro opakovanΘ spouÜt∞nφ), pak m∙₧eme zv²Üit v²konnost odklßdßnφm vlßken pro op∞tovnΘ pou₧itφ (namφsto jejich ruÜenφ a op∞tovnΘho vytvß°enφ). Pro odklßdßnφ vlßken, musφme udr₧ovat seznam vytvo°en²ch vlßken. Tento seznam m∙₧e b²t udr₧ovßn objektem, kter² pou₧φvß vlßkna nebo m∙₧eme pou₧φt globßlnφ prom∞nnou k ulo₧enφ odlo₧enΘho vlßkna.
    Kdy₧ je po₧adovßno novΘ vlßkno, pak je pou₧ito odlo₧enΘ vlßkno nebo vytvo°eno novΘ vlßkno (viz nßsledujφcφ funkce):
    TThreadList *pCache;
    ...
    TThread *GetThread(void)
    {
      TList *pList = pCache->LockList();
      TThread *NewThread;
      if (pList->Count) // ₧ßdnΘ vlßkno nenφ odlo₧eno
      {
        NewThread = (TThread *)pList->Items[0];
        pList->Delete(0); // odstran∞nφ ze seznamu
      }
      else
        NewThread=(TThread *)new TMyThread(true);//vytvo°enφ ale nespuÜt∞nφ
      pCache->UnlockList();
      return NewThread;
    }
    Jestli₧e vlßkno konΦφ provßd∞nφ je odlo₧eno (obsluha OnTerminate):
    void __fastcall TMyThread::Terminate(TObject *Sender)
    {
      pCache->Add(&this);
    }
    Kdy₧ aplikace konΦφ provßd∞nφ (nebo objekt, kter² vlastnφ vlßkna je ruÜen), pak odlo₧enß vlßkna musφ b²t uvoln∞na (obsluha OnDeactivate aplikace):
    void __fastcall TDataModule1::ApplicationDeactivate(TObject *Sender)
    {
      TList *pList = pCache->LockList();
      for (int i = pList->Count - 1; i >= 0; i--)
      {
        delete pList->Items[i];
        pList->Delete(i);
      }
      pCache->UnlockList();
    }
  3. Pokud ladφme vφcevlßknovΘ aplikace, pak m∙₧eme sledovat stav vÜech souΦasn∞ provßd∞n²ch vlßken nebo urΦit kterΘ vlßkno bude provßd∞no, kdy₧ provßd∞nφ je zastaveno bodem p°eruÜenφ. M∙₧eme pou₧φt dialogovΘ okno Stavu vlßken k manipulaci s vlßkny v naÜφ aplikaci. Toto okno zobrazφme volbou View | Threads. Kdy₧ nastane ladφcφ udßlost (bod p°eruÜenφ, provßd∞nφ) pak zobrazenφ stavu vlßkna indikuje stav ka₧dΘho vlßkna. V mφstnφ nabφdce okna jsou volby k lokalizaci odpovφdajφcφho zdroje nebo k ud∞lßnφ jinΘho vlßkna aktußlnφm. Jestli₧e vlßkno je oznaΦeno jako aktußlnφ, pak nßsledujφcφ krok nebo operace je relativnφ k tomuto vlßknu. Vlßkna jsou identifikovßna identifikaΦnφmi Φφsly (hodnota vlastnosti ThreadID).
  4. Vrßtφme se k naÜφ aplikaci z p°edchozφ kapitoly. Formulß° aplikace zv∞tÜφme a nastavφme u n∞j tyto vlastnosti: BorderStyle na bsDialog a Caption na Demonstrace °azenφ. Na formulß° p°idßme t°i komponenty Bevel a nastavφme u nich vlastnosti Top na 24, Width na 177 a Height na 233. U prvnφ z nich nastavφme Left na 8, u druhΘ na 192 a t°etφ na 376. Do ka₧dΘ z t∞chto komponent vlo₧φme komponentu PaintBox a nastavφme u nich stejnΘ hodnoty vlastnostφ jako u komponent Bevel. Levou z t∞chto komponent nazveme BubbleSortBox, prost°ednφ SelectionSortBox a pravou QuickSortBox. Nad ka₧dou z t∞chto komponent vlo₧φme Label s texty: Bublinkovß metoda, ╪azenφ v²b∞rem a Quick Sort. Do spodnφ Φßsti formulß°e vlo₧φme jeÜt∞ tlaΦφtko s textem ZaΦni °adit. Tφm je tento formulß° hotov. Do deklarace formulß°e vlo₧φme dalÜφ deklarace (viz nßsledujφcφ v²pis hlaviΦkovΘho souboru formulß°e):

  5. #ifndef ThSortH
    #define ThSortH
    #include <StdCtrls.hpp>
    #include <ExtCtrls.hpp>
    #include <Dialogs.hpp>
    #include <Forms.hpp>
    #include <Controls.hpp>
    #include <Graphics.hpp>
    #include <Classes.hpp>
    #include <SysUtils.hpp>
    #include <Messages.hpp>
    #include <Windows.hpp>
    #include <System.hpp>
    class TThreadSortForm : public TForm
    {
    __published:
     TButton *StartBtn;
     TPaintBox *BubbleSortBox;
     TPaintBox *SelectionSortBox;
     TPaintBox *QuickSortBox;
     TLabel *Label1;
     TBevel *Bevel1;
     TBevel *Bevel2;
     TBevel *Bevel3;
     TLabel *Label2;
     TLabel *Label3;
     void __fastcall BubbleSortBoxPaint(TObject *Sender);
     void __fastcall SelectionSortBoxPaint(TObject *Sender);
     void __fastcall QuickSortBoxPaint(TObject *Sender);
     void __fastcall FormCreate(TObject *Sender);
     void __fastcall StartBtnClick(TObject *Sender);
    private:
     int ThreadsRunning;
     void __fastcall RandomizeArrays(void);
     void __fastcall ThreadDone(TObject *Sender);
    public:
     void __fastcall PaintArray(TPaintBox *Box,const int *A,
          const int A_Size);
     virtual __fastcall TThreadSortForm(TComponent *Owner);
    };
    //--------------------------------------------------------------------
    typedef int TSortArray[115];
    typedef TSortArray *PSortArray;
    //--------------------------------------------------------------------
    extern PACKAGE TThreadSortForm *ThreadSortForm;
    extern bool ArraysRandom;
    extern int BubbleSortArray[115];
    extern int SelectionSortArray[115];
    extern int QuickSortArray[115];
    #endif
    Nßsleduje v²pis jednotky formulß°e:
    #include <vcl.h>
    #pragma hdrstop
    #include <stdlib.h>
    #include "thsort.h"
    #include "sortthd.h"
    #pragma resource "*.dfm"
    TThreadSortForm *ThreadSortForm;
    //--------------------------------------------------------------
    Boolean ArraysRandom;
    TSortArray BubbleSortArray, SelectionSortArray, QuickSortArray;
    __fastcall TThreadSortForm::TThreadSortForm(TComponent *Owner)
      : TForm(Owner)
    {
    }
    void __fastcall TThreadSortForm::PaintArray(TPaintBox *Box,
                    int const *A, int const ASize)
    {
      int i;
      TCanvas *canvas;
      canvas = Box->Canvas;
      canvas->Pen->Color = clRed;
      for (i=0; i < ASize; i++)
        PaintLine(canvas, i, A[i]);
    }
    //---------------------------------------------------------------
    void __fastcall TThreadSortForm::BubbleSortBoxPaint(TObject *)
    {
      PaintArray(BubbleSortBox, EXISTINGARRAY(BubbleSortArray));
    }
    void __fastcall TThreadSortForm::SelectionSortBoxPaint(TObject *)
    {
      PaintArray(SelectionSortBox, EXISTINGARRAY(SelectionSortArray));
    }
    void __fastcall TThreadSortForm::QuickSortBoxPaint(TObject * /*Sender*/)
    {
      PaintArray(QuickSortBox, EXISTINGARRAY(QuickSortArray));
    }
    //---------------------------------------------------------------
    void __fastcall TThreadSortForm::FormCreate(TObject * /*Sender*/)
    {
      RandomizeArrays();
    }
    void __fastcall TThreadSortForm::StartBtnClick(TObject * /*Sender*/)
    {
      TBubbleSort *bubble;
      TSelectionSort *selsort;
      TQuickSort *qsort;
      RandomizeArrays();
      ThreadsRunning = 3;
      bubble = new TBubbleSort(BubbleSortBox,
                               EXISTINGARRAY(BubbleSortArray));
      bubble->OnTerminate = ThreadDone;
      selsort = new TSelectionSort(SelectionSortBox,
                                   EXISTINGARRAY(SelectionSortArray));
      selsort->OnTerminate = ThreadDone;
      qsort = new TQuickSort(QuickSortBox, EXISTINGARRAY(QuickSortArray));
      qsort->OnTerminate = ThreadDone;
      StartBtn->Enabled = False;
    }
    //---------------------------------------------------------------------
    void __fastcall TThreadSortForm::RandomizeArrays()
    {
      int i;
      if (! ArraysRandom)
      {
        Randomize();
        for (i=0; i < ARRAYSIZE(BubbleSortArray); i++)
          BubbleSortArray[i] = random(170);
        memcpy(SelectionSortArray, BubbleSortArray,
               sizeof(SelectionSortArray));
        memcpy(QuickSortArray, BubbleSortArray, sizeof(QuickSortArray));
        ArraysRandom = True;
        Repaint();
      }
    }
    //---------------------------------------------------------------------
    void __fastcall TThreadSortForm::ThreadDone(TObject * /*Sender*/)
    {
      ThreadsRunning--;
      if (! ThreadsRunning)
      {
        StartBtn->Enabled = True;
        StartBtn->SetFocus();
        ArraysRandom = False;
      }
    }
    Pokuste se podle tohoto v²pisu vytvo°it b∞₧φcφ aplikaci a sna₧te se pochopit jednotlivΘ Φinnosti. Sna₧te se pochopit jak pracujφ vφcevlßknovΘ aplikace.
  6. P°idejte do p°edchozφ aplikace demonstraci dalÜφho zp∙sobu °azenφ (vlßkno, kterΘ jste vytvo°ili na zßv∞r p°edchozφ kapitoly).
26. Pou₧φvßnφ vlßken II