Threading::Thread^ in Klasse einsetzen



  • Ich habe ein größeres Programm und möchte dies nun auf mehrere CPU-Kernen ausführen.

    Ich habe das Problem hier einmal vereinfacht dargestellt, da mein eigentliches Programm jetzt viel zu unüberschaubar wäre.
    Sinngemäß habe ich zwei Klassen, wobei Objekte des Typs Klasse2 Member von Klasse1 sind.

    using namespace System::Threading;
    
    class Klasse2
    {
    public:
    	int PlusRechnen(int Zahl1, int Zahl2);
    	Klasse2();
    	~KLasse2();
    };
    
    class Klasse1
    {
    public:
    	Klasse1();
    	~Klasse1();
    	Threading ^Threads;
    	void RechenFunktion(int Z1, int Z2);
    	Klasse2 Rechner[2];
    	array<int> Threadergebnisse; //hab ich mir noch keine Gedanken drüber gemacht
    };
    
    Klasse1::RechenFunktion(int Z1, int Z2)
    {
    	//Threading ^Threads; //alternativ hier
    	if (Z1 > Z2)
    	{
    		Threads = gcnew Thread( gcnew ThreadStart( &Rechner[0].PlusRechnen(Z1,Z2) ) );
    	}
    	else
    	{
    		Threads = gcnew Thread( gcnew ThreadStart( &Rechner[1].PlusRechnen(Z1,Z2) ) );
    	}
    
    }
    
    int Klasse2::PlusRechnen(int Zahl1, int Zahl2)
    {
    	return Zahl1+Zahl2;
    }
    
    //ab hier nur Pseudocode!
    
    Threadhandler(int Zahl)
    {
    	Threadergebnisse.push_back(Zahl);
    }
    

    Ja ich weiß, dass dieser Code relativ wenig Sinn ergibt, aber er soll nur ein stark vereinfachtes Beispiel meines eigentlichen Problems darstellen. 😉

    Mein erstes Problem ist nun, dass der Compiler über die Deklarierung von "^Threads" in Klasse1 meckert:

    error C3265: Ein verwalteter 'Threads' kann nicht in einem nicht verwalteten 'Klasse1' deklariert werden
    

    Wenn ich ^Threads erst in meiner Funktion deklariere (siehe Kommentar im Code), dann kommt folgende Meldung:

    error C3364: "System::Threading::ThreadStart": Ungültiges Argument für den Delegatkonstruktor. Delegatziel muss ein Zeiger auf eine Memberfunktion sein.
    

    Kann mir da einer weiterhelfen? Ich hänge irgendwie fest. 😞



  • Hallo

    Klassisches Problem - Du mischst managed und unmanaged Code und bemerkst es nicht mal.
    ➡

    C++/CLI ist nicht geeignet für Anfänger und der einzig sinnvolle Einsatzbereich ist Interop zwischen managed und unmanaged Code!
    Siehe auch hier: http://www.c-plusplus.net/forum/263084
    Nimm entweder C++ oder C# (oder VB.NET) - nicht C++/CLI!!!

    Nun zu deinen konkreten Problemen:
    C3265: Mache Klasse1 und Klasse2 managed (ref class/struct, value class/struct)
    C3364: Guck Dir an wie man Delegaten benutzt! Im Forum hier gibts einige Threads dazu. Guck auch den ParameterizedThreadStart Delegat an (http://msdn.microsoft.com/en-us/library/system.threading.parameterizedthreadstart.aspx)



  • Ich habe jetzt meine Klassen auf Ref Class umgestellt. Aber nun habe ich folgendes Problem:

    Mit...

    ref class Klasse1
    {
    public:
        Klasse1();
        ~Klasse1();
        Threading ^Threads;
        void RechenFunktion(int Z1, int Z2);
        Klasse2 Rechner[2];
        array<int> Threadergebnisse; //hab ich mir noch keine Gedanken drüber gemacht
    };
    

    ... kann ich nun nicht mehr arbeiten, da man in Managed Classes auf diese Weise ja kein Array nutzen kann.
    Ein cli::array muss also her.

    ref class Klasse1
    {
    public:
        Klasse1();
        ~Klasse1();
        Threading ^Threads;
        void RechenFunktion(int Z1, int Z2);
        array<Klasse2^> ^Rechner; //ohne ^ gehts nicht
        array<int> Threadergebnisse; //hab ich mir noch keine Gedanken drüber gemacht
    };
    

    Der Konstruktor von Klasse2 soll allerdings auch ein paar Parameter verarbeiten können...

    ref class Klasse2
    {
    public:
        int PlusRechnen(int Zahl1, int Zahl2);
        Klasse2(int Startwert);
        ~KLasse2();
    };
    
    ref class Klasse1
    {
    public:
        Klasse1(int Startwert, int Arraygröße);
        ~Klasse1();
        Threading ^Threads;
        void RechenFunktion(int Z1, int Z2);
        array<Klasse2^> ^Rechner;
        array<int> Threadergebnisse; //hab ich mir noch keine Gedanken drüber gemacht
    };
    
    Klasse1::Klasse1(int Startwert, int Arraygröße)
    {
        Rechner->Resize(Arraygröße);
        for (i = 0; i < Arraygröße)
        {
            Rechner[i] = Klassse2::Klasse2(Startwert*i);
        }
    
    }
    

    Zwei Fragen hierzu:
    1. Kann man die Arraygröße auch gleich beim Aufruf von Klasse1 einstellen? Bei std::vector konnte ich das z.B. mit "Klasse1::Klasse1(int Startwert, int Arraygröße) : Rechner(Arraygröße,(Startwert))" erreichen.

    2. Bei der Zeile "Rechner[i] = Klassse2::Klasse2(Startwert*i);" meckert der Compiler, dass Klasse2^ nicht in Klasse2 konvertiert werden kann (C2440). 😞
    Auf Rechner[i]->Klasse2(Startwert) kann ich nicht zugreifen.



  • Ich schreib mal die Korrekturen rein:

    Klasse1::Klasse1(int Startwert, int Arraygröße) 
    { 
        /* Orginal Code von Dir
        Rechner->Resize(Arraygröße); 
        for (i = 0; i < Arraygröße) 
        { 
            Rechner[i] = Klassse2::Klasse2(Startwert*i); 
        } 
        */
    
        /* Korrigierter Code */
        Rechner = gcnew array<Rechner^>(Arraygrösse); 
        for (int i = 0; i < Rechner->Length; ++i) 
        { 
            Rechner[i] = gcnew Klasse2(Startwert*i); 
        }
    }
    

    Ich hoffe damit sind beide Frage beantwortet.

    Noch als Design Anmerkung:
    Es wäre vermutlich sinnvoller das Klasse2, die etwas berechnet, auch das Resultat speichert (bei sich) und nicht Klasse1 - die ruft ja nur die Berechnung auf.

    ➡ Lass mal die ThreadErgebnisse weg

    Edit:
    Design Anmerkung korrigiert.



  • Ahh! Dass ich darauf nicht gekommen bin... 🙄

    Kannst du mir vielleicht noch sagen, was ich machen muss, um die Arraygröße direkt bei der Initialisierung von Klasse1 zu bestimmen und nicht erst im Konstruktor?

    Klasse1::Klasse1(int Startwert, int Arraygröße) : Rechner(Arraygröße,(Startwert))
    

    Wenn ich es, wie oben beschrieben, hinten an den Konstruktor anhänge, kommt dieser Fehler:

    error C2359: 'Klasse1::Klasse2': Das Element vom Typ "Keine Klasse" erfordert einen einzelnen Initialisierungsausdruck
    

    Noch als Design Anmerkung:
    Es wäre vermutlich sinnvoller das Klasse2, die etwas berechnet, auch das Resultat speichert (bei sich) und nicht Klasse1 - die ruft ja nur die Berechnung auf.

    Dieser Code ist nur dazu da, um meine Probleme nachzustellen. 😉 Über 1+1 Rechnungen in Klassen bin ich dann doch schon ein wenig hinaus. ^^

    Edit:

    Rechner[i] = gcnew Klasse2(Startwert*i);
    

    An der Stelle, die du überarbeitet hast, kommt bei der Ausführung des kompilierten Programms jetzt immer folgender Fehler:

    System.NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
    

    Das Problem hatte ich schonmal, als ich noch ohne ref classes gearbeitet habe. Aber wie ich es beheben konnte, weiß ich nicht mehr. 😞



  • Kannst du mir vielleicht noch sagen, was ich machen muss, um die Arraygröße direkt bei der Initialisierung von Klasse1 zu bestimmen und nicht erst im Konstruktor?

    Ein Bsp.

    ref class B { };
    
    ref class A
    {
    public:
        A()
            : v_(gcnew array<B^>(2))
        { }
    
    private:
        array<B^>^ v_;
    };
    

    Aber Achtung, dabei ist erst das Array angelegt - die B Objekte im Array noch nicht!!
    Das wäre dann so:

    ref class B { };
    
    ref class A
    {
    public:
        A()
            : v_(gcnew array<B^>(2))
        {
            for (int i = 0; i < v_->Length; ++i)
            {
                v_[i] = gcnew B();
            }
        }
    
    private:
        array<B^>^ v_;
    };
    

    Edit:
    Noch zur NullRef. Exception:
    Hast Du zufällig noch Rechner->Resize(..) oder sowas drin? Ansonsten benutze einfach den Debugger - der sagt zeigt Dir was da Null ist.



  • Das erste hat gut funktioniert, vielen Dank dafür. 🙂

    Zur NullRef. Exception:
    Da stehen ansonsten keine weiteren Codezeilen zwischen der Deklaration des Konstruktors und der besagten Zeile bis auf ein int i (für die Schleife) und die Übergabe von "Arraygröße" an einen Klassemember.

    Wenn ich den Code folgendermaßen umändere, tritt der Fehler weiterhin auf:

    ref class Klasse1
    {
    public:
        Klasse1(int Startwert, int Arraygröße);
        ~Klasse1();
        Threading ^Threads;
        void RechenFunktion(int Z1, int Z2);
        static array<Klasse2^> ^Rechner = gcnew array<Klasse2^>(10);
    
        int Größe;
    
    };
    
    Klasse1::Klasse1(int Startwert, int Arraygröße)
    {
        Rechner->Resize(Rechner,Arraygröße);
        int i;
        Größe = Arraygröße; //eingefügt, um mein eigentliches Programm besser nachzustellen.
        Rechner->Resize(Arraygröße);
        for (i = 0; i < Arraygröße)
        {
            Rechner[i] = gcnew Klasse2(Startwert*i); //hier wird der Fehler ausgelöst
        }
    
    }
    

    Derzeit sieht mein Code - vom Prinzip her - so aus:

    ref class Klasse1
    {
    public:
        Klasse1(int Startwert, int Arraygröße);
        ~Klasse1();
        Threading ^Threads;
        void RechenFunktion(int Z1, int Z2);
        array<Klasse2^> ^Rechner;
    
        int Größe;
    
    };
    
    Klasse1::Klasse1(int Startwert, int Arraygröße) : Rechner(gcnew array<Klasse2^>(Arraygröße))
    {
        int i;
        Größe = Arraygröße; //eingefügt, um mein eigentliches Programm besser nachzustellen.
        Rechner->Resize(Arraygröße);
        for (i = 0; i < Arraygröße)
        {
            Rechner[i] = gcnew Klasse2(Startwert*i); //hier wird der Fehler ausgelöst
        }
    
    }
    

    Im Debugger finde ich leider nichts unauffälliges. 😞



  • Argh...
    1. Lass static aus dem Spiel - es ist falsch!
    2. Lass Resize(..) weg - es wird nicht benötigt!
    3. Zeige genau den Code, der bei Dir Probleme macht - ein kompilierbares Bsp!
    (Die Klasse Wurfel wurde erst jetzt ins Spiel gebracht, ist aber denke ich, für das Bsp unwichtig!)
    4. Was hat der Debugger gesagt? Hast Du Step By Step versucht? Einfach Breakpoint in den Konstruktor von Klasse1 und 2 setzen und danch F10 (Step) drücken.

    Edit:
    5.

    Rechner[i] = Klassse2::Klasse2(Startwert*i); //hier wird der Fehler ausgelöst

    Was soll das? Ich hab Dir gezeigt wie es richtig geht, siehe Bsp mit A und B



  • Tut mir leid, meine Konzentration hat etwas nachgelassen als ich meine Probleme hierhin übertragen wollte. 😞

    Also hier mein Originalcode:

    ////notwendige Structs
    
    struct Vektor
    {
    	int X,Y,Z;
    };
    
    struct CodeSample
    {
    	struct Vektor Start, Angle;
    	int Steps;
    	int CubeIndex;
    };
    
    ////Cubemanager-Klasse
    
    ref class Cubemanager
    {
    public:
    	int ParaCubes;
    
    	void Encrypt(wchar_t Character);
    
    	wchar_t Decrypt(CodeSample Sequenz);
    
    	array<Wurfel^> ^Cubes;
    
    	Code EnCryptCode;
    
    	bool Idle;
    
    	Cubemanager(long key, int Cubesize, int ParallelCubes);
    
    	~Cubemanager();
    };
    
    Cubemanager::Cubemanager(long Key, int Cubesize, int ParallelCubes) : Cubes(gcnew array<Wurfel^>(ParallelCubes))
    {
    	ParaCubes = ParallelCubes;
    	int i;
    	for (i=0;i<ParallelCubes;i++)
    	{
    		ParallelCubes, i);
    		//ShowMessage("Bereite Cubes vor.");
    		MessageBox::Show("Bereite Cubes vor."); //genutzt, um zu prüfen, ob mein Programm soweit kommt
                    //diese Meldung erscheint noch beim Ausführen des Codes
    		Cubes[i] = gcnew Wurfel(Key, Cubesize, ParallelCubes, i);
    		MessageBox::Show("Cubes erstellt."); //diese Meldung erscheint nicht mehr
    
    	}
    	Idle = true;
    };
    
    //////Wurfel-Klasse:
    
    static Vektor const NullVektor = {0,0,0};
    
    private ref class Wurfel  
    {
    public:
    	int Code437Part;
    
    	Wurfel(long Key, int Größe, int Aufteilung, int CubeIndex);
    
    	int Index;
    
    	int Kantenlänge;
    	~Wurfel();
    
    	CodeSample EnCrypt(wchar_t Sign);
    	CodeSample Seek(wchar_t Sign, bool Running, int Steps, bool Found, Vektor Active, Vektor Angle, Vektor StartAngle, Vektor Start);
    
    	wchar_t DeCrypt(CodeSample Sequenz);
    	wchar_t Find(CodeSample DeCryptCode, bool Running, int Steps, Vektor Active, Vektor Angle);
    
    	int CDFace; //Curent DeCryptFace
    	int CEFace; //Curent EnCryptFace
    	bool Enabled;
    	int Key;
    
    	std::vector<wchar_t> *Array, *PreArray;
    
    	void Arrays(int key);
    
    	void Collide(int &Wert, int Intensität);
    
    	int ArraySize;
    
    	std::vector< std::vector< std::vector<int> > > *Value;
    protected:
    	int Intensität(int Steps);
    
    	int EnCryptRand;
    };
    
    Wurfel::Wurfel(long Key, int Größe, int Aufteilung, int CubeIndex)// : Elements(Größe, Element(Aufteilung, Index, Key))
    {
    	srand(time(NULL));
    	EnCryptRand = (rand()%1000)*(rand()%7)*1000+(rand()%9)*100+(rand()%8)*10+(rand()%9);
    
    	Wurfel::Enabled = false;
    	if (Key < 0)
    	{
    		goto Ende;
    	}
    
    	Wurfel::Index = CubeIndex;
    
    	int Start;
    	CEFace = 1;
    	CDFace = 1;
    	Wurfel::Kantenlänge = Größe;
    	if (Index == 0) { Start = 0; } else { Start = 1; }
    
    	ArraySize = floorf(MaxSigns/Aufteilung+0.5)+3;
    	Array->resize(ArraySize);
    	PreArray->resize(ArraySize);
    	Resize(Value,Größe);
    
    	int Abschnitt = floorf(MaxSigns/Aufteilung * Index);
    	int i;
    
    	for(i=0;i<ArraySize-3;i++)
    	{
    		PreArray->at(i) = Code437[i+Abschnitt];
    	}
    
    	PreArray->at(i)=L'₦';
    	PreArray->at(i+1)=L'€';
    	PreArray->at(i+2)=L'Ð';
    
    	Wurfel::Enabled = true;
    	Arrays(Key);
    	Ende:;
    }
    

    Ich hoffe, der Code ist einigermaßen verständlich.

    Edit: Die Sache mit den Debuggerschritten habe ich jetzt mal versucht.
    Bei Cubes steht folgendes:
    - Cubes {Length=2} array<Wurfel^> ^
    [0] <Nicht definierter Wert> Wurfel^
    [1] <Nicht definierter Wert> Wurfel^



  • Ich habe eben nochmal genauer geschaut.

    Array->resize(ArraySize);
    PreArray->resize(ArraySize);
    

    Bei diesen Codezeilen stürzt das Programm mit besagtem Fehler ab.

    Edit: Wenn ich mittels push_back ein Element zu einem Vector hinzufügen möchte, kommt es ebenfalls zu diesem Fehler. 😞

    Edit: Ich habe den Fehler gefunden.
    Wenn ich zuvor einmalig die Variable mittels new neu zuweise, funktioniert es. 🙂



  • Ich habe nun mein gesamtes Programm auf diese ref classes umgestellt und alles soweit wieder zum Funktionieren gebracht. 😃

    Nun würde ich gern die Funktion "CodeSample EnCrypt(wchar_t Sign);" als Extrathread ausführen lassen.

    Eine Frage vorweg: Wenn mein Thread eine Funktion aufruft, wird diese dann auch von diesem Thread bearbeitet oder wird diese dann wieder vom Hauptthread bearbeitet?

    Wie lasse ich meinen Thread jetzt die gewünschte Funktion ausführen? Ich komme mit den Beispielen in der Hilfe nicht ganz klar, wenn ich es auf mein Programm anwenden möchte. 😕



  • Eine Frage vorweg: Wenn mein Thread eine Funktion aufruft, wird diese dann auch von diesem Thread bearbeitet oder wird diese dann wieder vom Hauptthread bearbeitet?

    Die Antwort ist eigentlich einfach, aber nicht so einfach zu Erklären.

    Sagen wirs mal so:
    Wenn dein Thread der einzige Aufrufer der Funktion ist, dann ist er der einzige der die Funktion ausführt.

    Es hindert dich niemand daran, die Funktion auch von einem anderen Thread aufzurufen - das musst Du dann einfach nicht machen, wenn Du das nicht willst.

    Simon

    Edit:
    Welche Bsp. verstehst Du nicht?



  • Das Beispiel lautet wie folgt:

    // Compile using /clr option.
    using namespace System;
    using namespace System::Threading;
    
    // Simple threading scenario:  Start a Shared method running
    // on a second thread.
    public ref class ThreadExample
    {
    public:
    
       // The ThreadProc method is called when the thread starts.
       // It loops ten times, writing to the console and yielding 
       // the rest of its time slice each time, and then ends.
       static void ThreadProc()
       {
          for ( int i = 0; i < 10; i++ )
          {
             Console::Write(  "ThreadProc: " );
             Console::WriteLine( i );
    
             // Yield the rest of the time slice.
             Thread::Sleep( 0 );
    
          }
       }
    
    };
    
    int main()
    {
       Console::WriteLine( "Main thread: Start a second thread." );
    
       // Create the thread, passing a ThreadStart delegate that
       // represents the ThreadExample::ThreadProc method.  For a 
       // delegate representing a static method, no object is
       // required.
       Thread^ oThread = gcnew Thread( gcnew ThreadStart( &ThreadExample::ThreadProc ) );
    
       // Start ThreadProc.  Note that on a uniprocessor, the new 
       // thread does not get any processor time until the main thread 
       // is preempted or yields.  Uncomment the Thread.Sleep that 
       // follows t.Start() to see the difference.
       oThread->Start();
    
       //Thread::Sleep(0);
       for ( int i = 0; i < 4; i++ )
       {
          Console::WriteLine(  "Main thread: Do some work." );
          Thread::Sleep( 0 );
    
       }
       Console::WriteLine(  "Main thread: Call Join(), to wait until ThreadProc ends." );
       oThread->Join();
       Console::WriteLine(  "Main thread: ThreadProc.Join has returned.  Press Enter to end program." );
       Console::ReadLine();
       return 0;
    }
    

    Noch ein Beispiel zu ParameterizedThreadStart:

    using namespace System;
    using namespace System::Threading;
    
    namespace SystemThreadingExample
    {
        public ref class Work
        {
        public:
            void StartThreads()
            {
    
                // To start a thread using a shared thread procedure, use
                // the class name and method name when you create the 
                // ParameterizedThreadStart delegate.
                //    AddressOf Work.DoWork)
                //
                Thread^ newThread = gcnew 
                    Thread(gcnew ParameterizedThreadStart(Work::DoWork));
    
                // Use the overload of the Start method that has a
                // parameter of type Object. You can create an object that
                // contains several pieces of data, or you can pass any 
                // reference type or value type. The following code passes
                // the integer value 42.
                newThread->Start(42);
    
                // To start a thread using an instance method for the thread 
                // procedure, use the instance variable and method name when 
                // you create the ParameterizedThreadStart delegate.
                Work^ someWork = gcnew Work;
                newThread = 
                    gcnew Thread(
                    gcnew ParameterizedThreadStart(someWork, 
                    &Work::DoMoreWork));
    
                // Pass an object containing data for the thread.
                //
                newThread->Start("The answer.");
            }
    
            static void DoWork(Object^ data)
            {
                Console::WriteLine("Static thread procedure. Data='{0}'", 
                    data);
            }
    
            void DoMoreWork(Object^ data)
            {
                Console::WriteLine("Instance thread procedure. Data='{0}'", 
                    data);
            }
        };
    }
    
    //Entry point of example application
    int main()
    {
        SystemThreadingExample::Work^ samplework = 
            gcnew SystemThreadingExample::Work();
        samplework->StartThreads();
    }
    
    // This code example produces the following output (the order 
    //   of the lines might vary):
    
    // Static thread procedure. Data='42'
    // Instance thread procedure. Data='The answer'
    

    Ich habe das jetzt wie folgt in mein Programm übertragen:

    ///Wurfel.h
    
    ref class Wurfel
    {
    (...)
        void EnCrypt(System::Object^ Sign);
    (...)
    };
    
    ///Wurfel.cpp
    
    Wurfel::Wurfel(long Key, int Größe, int Aufteilung, int CubeIndex)
    {
        srand(time(NULL));
        EnCryptRand = (rand()%1000)*(rand()%7)*1000+(rand()%9)*100+(rand()%8)*10+(rand()%9);
    
        Wurfel::Enabled = false;
        if (Key < 0)
        {
            goto Ende;
        }
    
        Wurfel::Index = CubeIndex;
    
        int Start;
        CEFace = 1;
        CDFace = 1;
        Wurfel::Kantenlänge = Größe;
        if (Index == 0) { Start = 0; } else { Start = 1; }
    
        ArraySize = floorf(MaxSigns/Aufteilung+0.5)+3;
        Array->resize(ArraySize);
        PreArray->resize(ArraySize);
        Resize(Value,Größe);
    
        int Abschnitt = floorf(MaxSigns/Aufteilung * Index);
        int i;
    
        for(i=0;i<ArraySize-3;i++)
        {
            PreArray->at(i) = Code437[i+Abschnitt];
        }
    
        PreArray->at(i)=L'₦';
        PreArray->at(i+1)=L'€';
        PreArray->at(i+2)=L'Ð';
    
        Wurfel::Enabled = true;
        Arrays(Key);
    
        //HINZUGEFÜGT:
        Compute = gcnew Thread(gcnew ParameterizedThreadStart(&Wurfel::EnCrypt(Sign)));
        /*error C2065: 'Sign': nichtdeklarierter Bezeichner
        error C3350: "System::Threading::ParameterizedThreadStart": Ein Delegatkonstruktor erwartet 2 Argument(e).
        error C2761: 'void Wurfel::EnCrypt(System::Object ^)': Die erneute Deklaration der Memberfunktion ist unzulässig
        error C2447: '{': Funktionsheader fehlt - Parameterliste im alten Stil?*/
    
        Compute = gcnew Thread(gcnew ParameterizedThreadStart(&Wurfel::EnCrypt(System::Object^ Sign))); //Alternative 1
        /*error C2065: 'Sign': nichtdeklarierter Bezeichner
        error C2275: 'System::Object': Ungültige Verwendung dieses Typs als Ausdruck
        error C3350: "System::Threading::ParameterizedThreadStart": Ein Delegatkonstruktor erwartet 2 Argument(e).
        error C2761: 'void Wurfel::EnCrypt(System::Object ^)': Die erneute Deklaration der Memberfunktion ist unzulässig
        error C2447: '{': Funktionsheader fehlt - Parameterliste im alten Stil?*/
    
        Compute = gcnew Thread(gcnew ParameterizedThreadStart(&Wurfel::EnCrypt())); //Alternative 2
        /*error C2660: 'Wurfel::EnCrypt': Funktion akzeptiert keine 0 Argumente
        error C3350: "System::Threading::ParameterizedThreadStart": Ein Delegatkonstruktor erwartet 2 Argument(e).
        error C2761: 'void Wurfel::EnCrypt(System::Object ^)': Die erneute Deklaration der Memberfunktion ist unzulässig
        error C2447: '{': Funktionsheader fehlt - Parameterliste im alten Stil?*/
    
        Compute = gcnew Thread(gcnew ParameterizedThreadStart(&Wurfel::EnCrypt)); //Alternative 3
        //error C3352: "void Wurfel::EnCrypt(System::Object ^)": Die angegebene Funktion stimmt nicht mit dem Delegattyp "void (System::Object ^)" überein.
        Ende;
    }
    
    void Wurfel::EnCrypt(System::Object^ Sign);
    {
        (...)
    }
    

    Ich verstehe irgendwie nicht, wie ich dem Thread sagen soll, dass er diese eine Funktion berechnen soll.

    Edit: Ich hab es hinbekommen! 🙂 Ich hab vergessen die Funktion static zu machen.



  • Ich bin dabei, die Threads in mein Programm zu implementieren und bin bisher auf zwei Dinge gestoßen, die in der Hilfe recht schwammig erklärt werden.

    1. Frage zu IsAlive

    IsAlive
    true, wenn dieser Thread gestartet und ordnungsgemäß beendet bzw. abgebrochen wurde, andernfalls false.

    Auch wenn mein Thread längst nicht mehr läuft, steht dieser Wert weiterhin auf true? Wie kann ich denn dann abfragen, ob mein Thread bereit ist, erneut gestartet zu werden?

    2. Muss ich einen Thread immer mittels Abort beenden? Beendet sich ein Thread von selbst, wenn alle Aufgaben abgearbeitet wurden? Wird IsAlive in dem Moment auf false gesetzt oder bleibt das weiterhin true?



  • 2. Muss ich einen Thread immer mittels Abort beenden?

    Nein. Im Gegenteil - mache das nie!

    Beendet sich ein Thread von selbst, wenn alle Aufgaben abgearbeitet wurden?

    Ja. Wenn die Thread Funktion verlassen wird, wird der Thread auch beendet.

    Ich würde einen Thread nicht erneut Starten, sondern einen neuen erzeugen oder noch besser benutze einen Threadpool! Und noch viiiiiil besser benutze das APM (Asynchronous Programming Model) - am besten mit der PowerThreading Library von Jeffrey Richter.



  • Ok, danke für die viele Hilfe, das ganze geht in großen Schritten voran. 🙂

    Aber ich stehe vor einem Problem, wofür ich keine Lösung finde. 😞

    In meinen Code habe ich arrays und vectors eingefügt, die als Buffer dienen sollen, damit sie nach und nach von den Threads abgearbeitet werden können:

    //structs.h
    
    struct Vektor
    {
    	int X,Y,Z;
    };
    
    struct CodeSample
    {
    	Vektor Start, Angle;
    	int Steps;
    	int CubeIndex;
    };
    
    struct Queing
    {
    	int Serial;
    	CodeSample* Sequence;
    };
    
    //Cubemanager.h
    
    ref class Cubemanager
    {
    public:
    (...)
        static std::vector<Queing*> *CodeQue; //siehe Konstruktor
        static array< array <int> ^> ^CryptQue;
        std::vector<CodeSample*> *NurEinTest;
        static std::vector<CodeSample*> *NochEinTest;
    (...)
    
    };
    
    //Cubemanager.cpp
    
    Cubemanager::Cubemanager(long Key, int Cubesize, int ParallelCubes, bool RunMultiThreaded)// : Cubes(gcnew array<Wurfel^>(ParallelCubes))
    {
    
    (...)   CodeQue = new std::vector<Queing*>(0); //Siehe Screenshot
            NochEinTest = new std::vector<CodeSample*>(0); //gleiches Problem
            CryptQue = gcnew array< array<int>^>(0); //funktioniert problemlos
            NurEinTest = new std::vector<CodeSample*>(0); //funktioniert ebenfalls
    
    (...)
    }
    

    Screenshot: http://img196.imageshack.us/img196/7053/speicherfehler.png

    Was genau könnte da los sein? Wenn ich den vector static mache, kann ich auf den Speicher nicht mehr zugreifen und wenn er nicht static ist, können meine Threads nicht mehr auf ihn zugreifen. 😞


Anmelden zum Antworten