Threading



  • Hallo zusammen, folgendes Problem:
    Hier der Code:

    ...

    System::Threading::Thread ^T = gcnew System::Threading::Thread(gcnew System::Threading::ThreadStart(&Ende));
    
    private: static void Sowieso()
    {
    Progressbar->Value = 50;
    }
    

    ...

    Wenn ich "static" schreibe:

    error C2227: Links von "->Value" muss sich ein Zeiger auf Klassen-/Struktur-/Union-/generischen Typ befinden.

    Wenn ich "static" weglasse:

    error C2276: '&': Ungültige Operation auf Ausdruck einer gebundenen Memberfunktion

    error C3350: "System::Threading::ThreadStart": Ein Delegatkonstruktor erwartet 2 Argument(e).

    Mfg



  • System::Threading::Thread ^T = gcnew System::Threading::Thread(gcnew System::Threading::ThreadStart(this, &Ende)); 
    
    private: void Sowieso() 
    { 
    Progressbar->Value = 50; 
    }
    

    Du musst dem ThreadStart Delegat mitteilen, auf welchem Objekt die Methode aufgerufen werden soll wenn diese NICHT statisch ist.

    Im obigen Code habe ich this als aktuelles Objekt angegeben.

    Simon



  • Hab ich auch schon versucht:

    error C2276: '&': Ungültige Operation auf Ausdruck einer gebundenen Memberfunktion

    error C3350: "System::Threading::ThreadStart": Ein Delegatkonstruktor erwartet 2 Argument(e).



  • Habe ich übersehen. Beim &Ende muss noch der Klassennamen vorne dran.
    Bsp: gcnew ThreadStart(this, &Form1::Ende)

    Simon



  • Soweit so gut:

    Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement Progressbar erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde.



  • Du musst den Aufruf von einem nicht UI Thread auf den UI Thread marshallen.
    Das kannst Du mit Invoke(..) machen.

    http://msdn.microsoft.com/de-de/library/system.windows.forms.control.invoke(VS.80).aspx



  • Oha !
    Das sieht aber nicht so leicht aus -.-

    Könntest du mir vllt ein Codebeispiel mit ordentlicher Beschreibung geben ?
    So versteh ich das am Besten...

    Wäre dir wirklich dankbar.





  • Leider auch kein Erfolg -.-



  • C++Lerner schrieb:

    Leider auch kein Erfolg -.-

    Es gibt ja sogar ein Bsp. auf der von mir geposteten MSDN Seite.
    Simon



  • Ich Blick da nicht durch (@ Invoke).
    Hab überhaupt keine Idee, wie ich das umsetzen soll:

    // The following code assumes a 'ListBox' and a 'Button' control are added to a form,
    // containing a delegate which encapsulates a method that adds items to the listbox.
    public ref class MyThreadClass
    {
    private:
       MyFormControl^ myFormControl1;
    
    public:
       MyThreadClass( MyFormControl^ myForm )
       {
          myFormControl1 = myForm;
       }
    
       void Run()
       {
          // Execute the specified delegate on the thread that owns
          // 'myFormControl1' control's underlying window handle.
          myFormControl1->Invoke( myFormControl1->myDelegate );
       }
    };
    

    Mein Versuch:

    public ref class MyThreadClass
    {
    private:
       ProgressBar^ PB;
    

    Das war´s, ab hier blick ich nicht mehr durch 🙄

    public:
       MyThreadClass( MyFormControl^ myForm )
       {
          myFormControl1 = myForm;
       }
    
       void Run()
       {
          myFormControl1->Invoke( myFormControl1->myDelegate );
       }
    };
    




  • Da ist wieder so viel Schnick-Schnack drin, bracuhe was ganz einfaches^^

    Könnte mir jemand vllt ein ganz knappes Beispiel geben ? Ohne Schnick-Schnack, wäre sehr nett.



  • Ist da viel drin??? 😕 musst halt die anderen Sprachen abschalten, ich finde da ist sowieso nur das nötigste drin...



  • xD, ja ist mir schon klar, ich meine der Quellcode sieht ziemlich voll aus o.O



  • Ich poste jetzt einfach mal meinen kompletten Header:

    #pragma once
    
    namespace t2 {
    
    	using namespace System;
    	using namespace System::ComponentModel;
    	using namespace System::Collections;
    	using namespace System::Windows::Forms;
    	using namespace System::Data;
    	using namespace System::Drawing;
    
    	/// <summary>
    	/// Zusammenfassung für Form1
    	///
    	/// Warnung: Wenn Sie den Namen dieser Klasse ändern, müssen Sie auch
    	///          die Ressourcendateiname-Eigenschaft für das Tool zur Kompilierung verwalteter Ressourcen ändern,
    	///          das allen RESX-Dateien zugewiesen ist, von denen diese Klasse abhängt.
    	///          Anderenfalls können die Designer nicht korrekt mit den lokalisierten Ressourcen
    	///          arbeiten, die diesem Formular zugewiesen sind.
    	/// </summary>
    	public ref class Form1 : public System::Windows::Forms::Form
    	{
    	public:
    		Form1(void)
    		{
    			InitializeComponent();
    			//
    			//TODO: Konstruktorcode hier hinzufügen.
    			//
    		}
    
    	protected:
    		/// <summary>
    		/// Verwendete Ressourcen bereinigen.
    		/// </summary>
    		~Form1()
    		{
    			if (components)
    			{
    				delete components;
    			}
    		}
    	private: System::Windows::Forms::Button^  button1;
    	private: System::Windows::Forms::ProgressBar^  progressBar1;
    	protected: 
    
    	private:
    		/// <summary>
    		/// Erforderliche Designervariable.
    		/// </summary>
    		System::ComponentModel::Container ^components;
    
    #pragma region Windows Form Designer generated code
    		/// <summary>
    		/// Erforderliche Methode für die Designerunterstützung.
    		/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
    		/// </summary>
    		void InitializeComponent(void)
    		{
    			this->button1 = (gcnew System::Windows::Forms::Button());
    			this->progressBar1 = (gcnew System::Windows::Forms::ProgressBar());
    			this->SuspendLayout();
    			// 
    			// button1
    			// 
    			this->button1->Location = System::Drawing::Point(12, 81);
    			this->button1->Name = L"button1";
    			this->button1->Size = System::Drawing::Size(75, 23);
    			this->button1->TabIndex = 0;
    			this->button1->Text = L"button1";
    			this->button1->UseVisualStyleBackColor = true;
    			this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);
    			// 
    			// progressBar1
    			// 
    			this->progressBar1->Location = System::Drawing::Point(12, 158);
    			this->progressBar1->Name = L"progressBar1";
    			this->progressBar1->Size = System::Drawing::Size(260, 23);
    			this->progressBar1->TabIndex = 1;
    			// 
    			// Form1
    			// 
    			this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
    			this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
    			this->ClientSize = System::Drawing::Size(284, 264);
    			this->Controls->Add(this->progressBar1);
    			this->Controls->Add(this->button1);
    			this->Name = L"Form1";
    			this->Text = L"Form1";
    			this->ResumeLayout(false);
    
    		}
    #pragma endregion
    
    	private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e)
    			 {
    				 System::Threading::Thread^ T1 = gcnew System::Threading::Thread(gcnew System::Threading::ThreadStart(this,&Form1::Do));
    				 T1->Start();
    			 }
    
    	private: void Do()
    			 {
    				 progressBar1->Value = 50;
    			 }
    	};
    }
    

    Der Wille ist ja wahrscheinlich klar, die Umsetzung falsch.
    Ich weiß UI-Thread, aber ich hab keine Ahnung 😕 😕
    Wäre wirklich nett, wenn mir jemand den Code so umschreiben könnte, dass er funktioniert. So lern ich das wahrscheinlich am besten ! 🙂



  • private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e)
    		 {
    			 System::Threading::Thread^ T1 = gcnew System::Threading::Thread(gcnew System::Threading::ThreadStart(this,&Form1::Do));
    			 T1->Start();
    		 }
    
    private: delegate void DoDelegate();
    
    private: void Do()
    		 {
    			 if (!InvokeRequired)
    			 {
    				progressBar1->Value = 50;
    			 }
    			 else
    			 {
    				 Invoke(gcnew DoDelegate(this, &Form1::Do));
    			 }
    		 }
    };
    


  • Super !
    Hat geklappt, danke !

    Jetzt werde ich mal zusehen, dass ich den ganzen Code noch verstehe, sollte aber kein Problem sein !

    Danke nochmal an alle 😃



  • Hallo,

    eine weiter Möglichkeit (nicht unbedingt ratsam) den Fehler

    Threadübergreifender Zugriff auf Steuerelement

    wegzubekommen, ist z.B. im Konstruktor der Form1 folgendes hinzuzufügen:

    Form1::CheckForIllegalCrossThreadCalls=false;
    

    Jetzt aber zu meiner Frage:
    Ich hab das Beispiel eben auch mal ausprobiert (1:1 übernommen) und hatte eigentlich erwartet, dass das Fenster (also die Form1) nicht blockiert!
    Deswegen bette ich die Methode Do() ja in einen eigenen Thread, oder nicht?
    Bei mir blockiert das Fenster trotzdem, bis mein Testzähler durchgelaufen ist.

    rufe ich die Methode Do() so auf:

    ...
    	private: 
    		System::Void btn_Click(System::Object^  sender, System::EventArgs^  e)
    		{
    			System::Diagnostics::Debug::WriteLine("CLICK");
    			Do();
    		}
    
    		delegate void DoDelegate(); 
    
    		void Do()
    		{			
    				int i=0;
                    while(i<200)
    				{
    					System::Diagnostics::Debug::Write("Do it ");
    					System::Diagnostics::Debug::WriteLine(i);
    					i++;
    				}
    		}
    	};// end class Form1
    
    } // end namespace
    

    verhält sie sich bei mir exakt so wie das obige Beispiel 😕



  • Hm...ist bei mir auch so ( hab es vorhin erst richtig ausprobiert, hatte kaum Zeit... )

    Frage:

    Form1::CheckForIllegalCrossThreadCalls=false;
    

    Hat das irgendwelche Nebenwirkungen ???

    Ich poste gleich mal meinen gesammten Header, dann kann ja vllt mal jemand verbesserungsvorschläge geben, damit die Form1 nicht so lagt...


Anmelden zum Antworten