Threading::Thread^ in Klasse einsetzen
-
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.