Thread-Instanzen - wie viele sind möglich?



  • Ok, habe in der Execute-Methode noch mal auf mögliche Fehler untersucht.
    Dabei stelle ich fest, dass bei gesetzter Flag _bUpDown = true alles nach Wunsch läuft.
    Bei _bUpDown = false ist der Wert von i2 immer 160(!).

    int i2;
    int iGrz = 160;
    for(int i=0; i<iGrz; i++){
        Sleep(_iArray[i]); // Thread schlafen schicken
        if(_bUpDown){
            i2 = i;
        }else{
            i2 = iGrz - i;
        }
        Edit_Ausgabe->Text = "Thr. " + _asAusdruck + " - " + IntToStr(i2);
        DM_Farbe->gfldShape[i2]->Brush->Color = _colA;
    }
    

    Wie kann das sein?



  • Wieder keine Ahnung, was das für ein Codeschnippsel ist. Mal ins Blaue geraten, du weißt schon, dass man Ressourcen, die von mehreren Threads verändert werden können synchronisieren muss?
    Die Anzahl der Threads mag unbegrenzt sein, aber die Anzahl der Handles ist es nicht. Allerdings kann man normal schon viele Handles haben.



  • Habe gedacht, ich poste hier nicht mehr Code als nötig. Aber wenn mehr nötig ist ... ok.
    Die funktionierende Variante ist mit xx1, die andere mit xx2 in der Execute-Methode markiert.
    Bin sehr gespannt zu erfahren, warum nicht beide funktionieren!

    // Unit_Thread_Matrix.h
    //---------------------------------------------------------------------------
    
    #ifndef Unit_Thread_MatrixH
    #define Unit_Thread_MatrixH
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    
    #include "Unit_DM_Farbe.h"
    
    //---------------------------------------------------------------------------
    class TThread_Matrix : public TThread
    {
        typedef struct tagTHREADNAME_INFO
        {
          DWORD dwType;     // muß 0x1000 sein
          LPCSTR szName;    // Zeiger auf Name (in user addr space)
          DWORD dwThreadID; // Thread-ID (-1=caller thread)
          DWORD dwFlags;    // Reserviert für spätere Verwendung, muß 0 sein
        } THREADNAME_INFO;
    private:
        void SetName();
    protected:
    
        TEdit *Edit_Ausgabe; // Zeiger auf das Ausgabe-Edit-Feld
        AnsiString _asAusdruck;
        TColor _colA;
        int *_iArray;
        bool _bUpDown;
    
        void __fastcall Execute();
    public:
    
        __fastcall TThread_Matrix(bool CreateSuspended, TEdit *Edit, AnsiString asAusdruck,
                                  TColor colA, int *iArray, bool bUpDown);
    };
    //---------------------------------------------------------------------------
    #endif
    
    // Unit_Thread_Matrix.cpp
    //---------------------------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
    
    #include "Unit_Thread_Matrix.h"
    #pragma package(smart_init)
    //---------------------------------------------------------------------------
    
    //   Wichtig: Methoden und Eigenschaften von Objekten der VCL können nur
    //   in Methoden verwendet werden, die Synchronize aufrufen, z.B.:
    //
    //      Synchronize(UpdateCaption);
    //
    //   wobei UpdateCaption so aussehen könnte:
    //
    //      void __fastcall TThread_Matrix::UpdateCaption()
    //      {
    //        Form1->Caption = "In Thread aktualisiert";
    //      }
    //---------------------------------------------------------------------------
    
    __fastcall TThread_Matrix::TThread_Matrix(bool CreateSuspended, TEdit *Edit, AnsiString asAusdruck,
                                              TColor colA, int *iArray, bool bUpDown) : TThread(CreateSuspended)
    {
        FreeOnTerminate = true; // wenn der Thread gekillt wird, dann gleich entfernen
    
        // Auf die nachfolgenden Referenzen und Übergabeparameter wird in der Execute-Methode zugegriffen
        //
        Edit_Ausgabe = Edit; // die Ausgabe erfolgt in einem Edit-Feld das auf der Mainform liegt
        _asAusdruck = asAusdruck;
        _colA = colA;
        _iArray = iArray;
        _bUpDown = bUpDown;
    }
    //---------------------------------------------------------------------------
    
    void TThread_Matrix::SetName()
    {
            THREADNAME_INFO info;
            info.dwType = 0x1000;
            info.szName = "Thread_Matrix";
            info.dwThreadID = -1;
            info.dwFlags = 0;
    
            __try
            {
                     RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD),(DWORD*)&info );
            }
            __except (EXCEPTION_CONTINUE_EXECUTION)
            {
            }
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TThread_Matrix::Execute()
    {
        SetName();
        //---- Hier den Thread-Code plazieren----
    
        // solange der Thread nicht gekillt wurde
        while(!Terminated)
        {
    
            // (xx1) diese Variante funktioniert
            // Erl. siehe Doku 28.11.13
            if(_bUpDown){
                for(int i=0; i<DM_Farbe->giShapeAnz; i++){
                    Sleep(_iArray[i]); // Thread schlafen schicken
                    Edit_Ausgabe->Text = "Thr. " + _asAusdruck + " - " + IntToStr(i);
                    DM_Farbe->gfldShape[i]->Brush->Color = _colA;
                }
            }else{
                for(int i=DM_Farbe->giShapeAnz-1; i>-1; i--){
                    Sleep(_iArray[i]); // Thread schlafen schicken
                    Edit_Ausgabe->Text = "Thr. " + _asAusdruck + " - " + IntToStr(i);
                    DM_Farbe->gfldShape[i]->Brush->Color = _colA;
                }
            }
    
            // (xx2)
            /* diese wegen _bUpDown-Problem nicht.
            int i2;
            int iGrz = 160;
            for(int i=0; i<iGrz; i++){
                Sleep(_iArray[i]); // Thread schlafen schicken
                if(_bUpDown){
                    i2 = i;
                }else{
                    i2 = iGrz - i;
                }
                Edit_Ausgabe->Text = "Thr. " + _asAusdruck + " - " + IntToStr(i2);
                DM_Farbe->gfldShape[i2]->Brush->Color = _colA;
            }
            */
        }
    }
    //---------------------------------------------------------------------------
    
    // Unit_DM_Farbe.h
    //---------------------------------------------------------------------------
    #ifndef Unit_DM_FarbeH
    #define Unit_DM_FarbeH
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    #include <SyncObjs.hpp> // für TEvent
    //---------------------------------------------------------------------------
    #define MATRIX_ROW 10
    #define MATRIX_COL 16
    //---------------------------------------------------------------------------
    class TDM_Farbe : public TDataModule
    {
    __published:	// Von der IDE verwaltete Komponenten
            void __fastcall DataModuleCreate(TObject *Sender);
    
    private:	// Anwender-Deklarationen
    
    public:		// Anwender-Deklarationen
    
            int giShapeAnz;
            DynamicArray<TShape* > gfldShape;
    
            __fastcall TDM_Farbe(TComponent* Owner);
            void __fastcall TDM_Farbe::sub_erzeuge_DynArr_fldShape(TForm *Form, TPanel *PanelShape, int iShapeAnz,
                                                                   DynamicArray<TShape* > fldShape);
            void __fastcall TDM_Farbe::sub_zerstoere_DynArr_fldShape(TForm *Form, TPanel *PanelShape, int iShapeAnz,
                                                                     DynamicArray<TShape* > fldShape);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TDM_Farbe *DM_Farbe;
    //---------------------------------------------------------------------------
    #endif
    
    // Unit_DM_Farbe.cpp
    //---------------------------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
    
    #include "Unit_DM_Farbe.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TDM_Farbe *DM_Farbe;
    //---------------------------------------------------------------------------
    __fastcall TDM_Farbe::TDM_Farbe(TComponent* Owner)
            : TDataModule(Owner)
    {
    }
    //---------------------------------------------------------------------------
    void __fastcall TDM_Farbe::DataModuleCreate(TObject *Sender)
    {
        giShapeAnz = MATRIX_COL * MATRIX_ROW;
        gfldShape.Length = giShapeAnz; // Feldlänge setzen
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TDM_Farbe::sub_erzeuge_DynArr_fldShape(TForm *Form, TPanel *PanelShape, int iShapeAnz, DynamicArray<TShape* > fldShape)
    {
        // Zweck: nomen est omen
    
        // erwartet:
        // Form: das aufrufende Formular
        // Panel: den auf dem Formular enthaltenen Panel mit den TShapes
        // iShapeAnz: Anzahl
        // DynamicArray fldShape: das die Referenzen zu den zur Designzeit erstellten TShape-Objekten enthält
    
        for(int i=0; i<iShapeAnz; i++){
            fldShape[i] = new TShape(Form);
            fldShape[i]->Tag = i;
            fldShape[i]->Visible = false; // müssen nicht sichtbar sein, dienen nur als Referenz
        }
    
        // Shapes von PanelShape durchlaufen und den dynamisch erzeugten zuweisen
        TControl *ChildControl;
        for(int i=0; i<PanelShape->ControlCount; i++){
            ChildControl = PanelShape->Controls[i];
            if(ChildControl->ClassNameIs("TShape")){
                fldShape[i] = dynamic_cast<TShape*>(ChildControl);
            }
        }
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TDM_Farbe::sub_zerstoere_DynArr_fldShape(TForm *Form, TPanel *PanelShape, int iShapeAnz, DynamicArray<TShape* > fldShape)
    {
        // Zweck: nomen est omen
    
        for(int i=0; i<iShapeAnz; i++){
            if(gfldShape.Length > 0){ delete fldShape[i]; }
        }
        // Speicher freigeben.
        fldShape.Length = 0; // Speicher freigeben
    }
    //---------------------------------------------------------------------------
    
    // Unit_Form_Bsp02_Matrix.h
    //---------------------------------------------------------------------------
    
    #ifndef Unit_Form_Bsp02_MatrixH
    #define Unit_Form_Bsp02_MatrixH
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    
    #include "Unit_DM_Farbe.h"
    #include "Unit_Thread_Matrix.h"
    #include <ExtCtrls.hpp>
    
    //---------------------------------------------------------------------------
    class TForm_Bsp02_Matrix : public TForm
    {
    __published:	// Von der IDE verwaltete Komponenten
            TButton *btn01_Start;
            TEdit *Edit1;
            TButton *btn01_Stopp;
            TButton *btn02_Start;
            TButton *btn02_Stopp;
            TButton *btn03_Start;
            TButton *btn03_Stopp;
            TEdit *Edit2;
            TEdit *Edit3;
            TLabel *Label1;
            TPanel *pnl_ShapeA;
            TShape *Shape1;
            TShape *Shape2;
            TShape *Shape3;
            //(... ebenso für Shape4 bis Shape159)
            TShape *Shape160;
            TButton *btn04_Start;
            TButton *btn04_Stopp;
            TEdit *Edit4;
            TButton *btn05_Start;
            TButton *btn05_Stopp;
            TEdit *Edit5;
            TButton *btn06_Start;
            TButton *btn06_Stopp;
            TEdit *Edit6;
            TButton *btn07_Start;
            TButton *btn07_Stopp;
            TEdit *Edit7;
            TButton *btn08_Start;
            TButton *btn08_Stopp;
            TEdit *Edit8;
            void __fastcall btn01_StartClick(TObject *Sender);
            void __fastcall btn01_StoppClick(TObject *Sender);
            void __fastcall btn02_StartClick(TObject *Sender);
            void __fastcall btn02_StoppClick(TObject *Sender);
            void __fastcall btn03_StartClick(TObject *Sender);
            void __fastcall btn03_StoppClick(TObject *Sender);
            void __fastcall FormShow(TObject *Sender);
            void __fastcall FormCreate(TObject *Sender);
            void __fastcall FormDestroy(TObject *Sender);
            void __fastcall btn04_StartClick(TObject *Sender);
            void __fastcall btn04_StoppClick(TObject *Sender);
            void __fastcall btn05_StartClick(TObject *Sender);
            void __fastcall btn05_StoppClick(TObject *Sender);
            void __fastcall btn06_StartClick(TObject *Sender);
            void __fastcall btn06_StoppClick(TObject *Sender);
            void __fastcall btn07_StartClick(TObject *Sender);
            void __fastcall btn07_StoppClick(TObject *Sender);
            void __fastcall btn08_StartClick(TObject *Sender);
            void __fastcall btn08_StoppClick(TObject *Sender);
    private:	// Anwender-Deklarationen
    
            bool mbEinmal;
            int *miArray;
            TThread_Matrix *Thread_Matrix1; // Zeiger auf den Thread deklarieren
            TThread_Matrix *Thread_Matrix2; // Zeiger auf den Thread deklarieren
            TThread_Matrix *Thread_Matrix3; // Zeiger auf den Thread deklarieren
            TThread_Matrix *Thread_Matrix4; // Zeiger auf den Thread deklarieren
            TThread_Matrix *Thread_Matrix5; // Zeiger auf den Thread deklarieren
            TThread_Matrix *Thread_Matrix6; // Zeiger auf den Thread deklarieren
            TThread_Matrix *Thread_Matrix7; // Zeiger auf den Thread deklarieren
            TThread_Matrix *Thread_Matrix8; // Zeiger auf den Thread deklarieren
    
    public:		// Anwender-Deklarationen
            __fastcall TForm_Bsp02_Matrix(TComponent* Owner);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm_Bsp02_Matrix *Form_Bsp02_Matrix;
    //---------------------------------------------------------------------------
    #endif
    
    // Unit_Form_Bsp02_Matrix.cpp
    //---------------------------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
    #include "Unit_Form_Bsp02_Matrix.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm_Bsp02_Matrix *Form_Bsp02_Matrix;
    //---------------------------------------------------------------------------
    __fastcall TForm_Bsp02_Matrix::TForm_Bsp02_Matrix(TComponent* Owner)
            : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm_Bsp02_Matrix::FormCreate(TObject *Sender)
    {
        // Flag soll/darf nur einmal ausgeführt werden in FormShow
        mbEinmal = false;
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm_Bsp02_Matrix::FormDestroy(TObject *Sender)
    {
        delete [] miArray;
        DM_Farbe->sub_zerstoere_DynArr_fldShape(this, this->pnl_ShapeA, DM_Farbe->giShapeAnz, DM_Farbe->gfldShape);
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm_Bsp02_Matrix::FormShow(TObject *Sender)
    {
        // Um Bildschirmflackern vorzubeugen
        this->DoubleBuffered = true;
        pnl_ShapeA->DoubleBuffered = true;
    
        // Flag soll/darf nur einmal ausgeführt werden in FormShow
        if(!mbEinmal){
            mbEinmal = true;
    
            DM_Farbe->giShapeAnz = 160;
    
            // muss unter Destroy auch wieder zerstört werden (!!)
            DM_Farbe->sub_erzeuge_DynArr_fldShape(this, this->pnl_ShapeA, DM_Farbe->giShapeAnz, DM_Farbe->gfldShape);
    
            miArray = new int[DM_Farbe->giShapeAnz];
            for(int i=0; i<DM_Farbe->giShapeAnz; i++){
                miArray[i] = i;
            }
    
            // Suspended Thread erstellen, d.h. der Thread läuft erstmal nicht los (erstes Argument = true)
    
            Thread_Matrix1 = new TThread_Matrix(true, Edit1, "1", clRed, miArray, true); // 1
            Thread_Matrix1->Priority = tpIdle; // Idle-Thread erstellen
    
            Thread_Matrix2 = new TThread_Matrix(true, Edit2, "2", clGreen, miArray, true); // 2
            Thread_Matrix2->Priority = tpIdle; // Idle-Thread erstellen
    
            Thread_Matrix3 = new TThread_Matrix(true, Edit3, "3", clBlue, miArray, true); // 3
            Thread_Matrix3->Priority = tpIdle; // Idle-Thread erstellen
    
            Thread_Matrix4 = new TThread_Matrix(true, Edit4, "4", clYellow, miArray, false); // 4
            Thread_Matrix4->Priority = tpIdle; // Idle-Thread erstellen
    
            Thread_Matrix5 = new TThread_Matrix(true, Edit5, "5", clTeal, miArray, false); // 5
            Thread_Matrix5->Priority = tpIdle; // Idle-Thread erstellen
    
            Thread_Matrix6 = new TThread_Matrix(true, Edit6, "6", clFuchsia, miArray, false); // 6
            Thread_Matrix6->Priority = tpIdle; // Idle-Thread erstellen
    
            Thread_Matrix7 = new TThread_Matrix(true, Edit7, "7", clBlack, miArray, false); // 7
            Thread_Matrix7->Priority = tpIdle; // Idle-Thread erstellen
    
            Thread_Matrix8 = new TThread_Matrix(true, Edit8, "8", clWhite, miArray, false); // 8
            Thread_Matrix8->Priority = tpIdle; // Idle-Thread erstellen
        }
    }
    //---------------------------------------------------------------------------
    
    void __fastcall TForm_Bsp02_Matrix::btn01_StartClick(TObject *Sender)
    {
        Thread_Matrix1->Resume(); // startet den Thread
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm_Bsp02_Matrix::btn01_StoppClick(TObject *Sender)
    {
        Thread_Matrix1->Suspend(); // hält den Thread an
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm_Bsp02_Matrix::btn02_StartClick(TObject *Sender)
    {
        Thread_Matrix2->Resume(); // startet den Thread
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm_Bsp02_Matrix::btn02_StoppClick(TObject *Sender)
    {
        Thread_Matrix2->Suspend(); // hält den Thread an
    }
    //---------------------------------------------------------------------------
    
    //(... für weitere 6 Buttons)
    


  • Die Varianten unterscheiden sich erheblich:

    xx1: verwendet 'DM_Farbe->giShapeAnz' für die Arraygröße (Zeile 108,114).
    xx2: den konstanten Wert 160 (Zeile 125, 126).

    - osdt



  • Nachtrag: wenn Du wissen möchtest weshalb Variante xx2 nicht funktioniert, schau dir mal die Funktion ...

    TDM_Farbe::sub_erzeuge_DynArr_fldShape(TForm *Form, TPanel *PanelShape, int iShapeAnz, DynamicArray<TShape* > fldShape)
    

    ... an. 'DynamicArray<TShape* > fldShape' wird als WERT und nicht als Referenz übergeben, alle Änderungen gehen verloren. Außerdem ist der Parameter sinnlos weil das Array eine Member Variable von TDM_Farbe (gfldShape) selbst ist.

    - osdt



  • osdt schrieb:

    Nachtrag: wenn Du wissen möchtest weshalb Variante xx2 nicht funktioniert, schau dir mal die Funktion ...

    TDM_Farbe::sub_erzeuge_DynArr_fldShape(TForm *Form, TPanel *PanelShape, int iShapeAnz, DynamicArray<TShape* > fldShape)
    

    ... an. 'DynamicArray<TShape* > fldShape' wird als WERT und nicht als Referenz übergeben, alle Änderungen gehen verloren. Außerdem ist der Parameter sinnlos weil das Array eine Member Variable von TDM_Farbe (gfldShape) selbst ist.

    - osdt

    Danke! Den Erklärungen mit Wert und Referenz kann ich gut folgen, macht Sinn. Auch, dass der Parameter überflüssig ist, da eh schon Member-Variable, verstehe ich.

    Nur - warum funktioniert es trotzdem und zwar mit bis zu acht Instanzen?
    Und außerdem erklärt das nicht das 'dubiose' Verhalten der Flag '_bUpDown'.

    Zum Ausprobieren und Selber-mal-Anfassen hier der Link zu Quellcode und exe:
    http://www.eoleo.de/cpp/v_x_for_newsgroup_131118.zip



  • Leo Freitag schrieb:

    Zum Ausprobieren und Selber-mal-Anfassen hier der Link zu Quellcode und exe:
    http://www.eoleo.de/cpp/v_x_for_newsgroup_131118.zip

    Du musst bedenken, dass nicht so viele mit Borland C++ arbeiten und das haben (ich habs nicht), das ist schon recht exotisch. Aber ohne das auszuprobieren ist es jetzt tatsächlich nicht so einfach, in so viel Code sofort durchzublicken.



  • Ich habe den 'Code' eben nochmal überflogen. Er enthält so viele Fehler, dass ich nicht weiß wo ich anfangen soll.
    Deshalb antworte ich jetzt nur auf die konkreten Fragen:

    Nur - warum funktioniert es trotzdem und zwar mit bis zu acht Instanzen?

    DynamicArray<> hält wahrscheinlich nur einen Pointer auf die eigentlichen Daten. Deshalb ist es innerhalb deiner Funktion eben doch änderbar, sofern kein neuer Speicherbereich reserviert werden muss.

    Und außerdem erklärt das nicht das 'dubiose' Verhalten der Flag '_bUpDown'.

    siehe Änderung (iGrz - 1) und Kommentar Zeile 9:

    // (xx2)
            int i2;
            int iGrz = 160;
            for(int i=0; i<iGrz; i++){
                Sleep(_iArray[i]); // Thread schlafen schicken
                if(_bUpDown){
                    i2 = i;
                }else{
                    i2 = (iGrz - 1) - i;  // i2 = 159 ... 0
                }
                Edit_Ausgabe->Text = "Thr. " + _asAusdruck + " - " + IntToStr(i2);
                DM_Farbe->gfldShape[i2]->Brush->Color = _colA;
            }
    

    Noch eine Bemerkung: um C++ zu erlernen solltest Du vielleicht mit einfachen Consolen Programmen anfangen.

    - osdt



  • Besten Dank schonmal.

    osdt schrieb:

    Ich habe den 'Code' eben nochmal überflogen. Er enthält so viele Fehler, dass ich nicht weiß wo ich anfangen soll.
    (...)

    Ja, 'i2 = iGrz-i' anstatt 'i2 = (iGrz-1)-i' war ein blöder Fehler mit irreführenden Folgen. Und in Zusammenhang mit 'DM_Farbe->giShapeAnz' gibt es Überflüssiges.
    Und wo sich in dem Code die anderen 'vielen Fehler' verstecken, würde mich natürlich brennend interessieren ... ich könnte was dazulernen!

    Gruß
    Leo



  • Hab´ mir ebenfalls nicht den ganzen Code angeguckt, aber was mir aufgefallen ist:
    Du veränderst in einem Thread Eigenschaften eines GUI Elements, und das darf man bei der VCL nicht. Das kann gut gehen, muss aber nicht. Das Perfide dabei ist, dass man es oft nicht merkt, weil der Code zwar kompiliert und das Programm nicht abstürzt, aber sich die GUI Elemente nicht so verhalten, wie man sich das vorstellt. Du solltest alle Änderungen an GUI Elementen im VCL Hauptthread durchführen, guck dir dazu mal die Beschreibung vonThread::Synchronize an.


Anmelden zum Antworten