Asynchroner Aufruf von Delegates



  • Hallo,

    hier ist ein C#-Beispiel wie man Delegates asynchron aufrufen kann:

    namespace AsynchDelegates
    {
    public class ClassWithDelegate
    {
    	public delegate int DelegateThatReturnsInt();
    	public event DelegateThatReturnsInt theDelegate;
    
    	public void Run()
    	{
    		for ( ; ; )
    		{
    			Thread.Sleep( 500 );
    			if ( theDelegate != null )
    			{
    				// Alle delegierten Methoden explizit aufrufen
    				foreach (
    				DelegateThatReturnsInt del in
    				theDelegate.GetInvocationList() )
    				{
    					// Asynchron aufrufen
    					// Das Delegate als Status-Objekt übergeben
    					del.BeginInvoke( new AsyncCallback( ResultsReturned ),del);
    				}
    			}
    		}
    	}
    
    	private void ResultsReturned( IAsyncResult iar )
    	{
    		// Das Status-Objekt zurück in den Delegate-Typ wandeln
    		DelegateThatReturnsInt del = (DelegateThatReturnsInt ) iar.AsyncState;
    		// Beim Delegate EndInvoke aufrufen, um das Ergebnis zu bekommen
    		int result = del.EndInvoke( iar );
    		// Ergebnis anzeigen
    		Console.WriteLine( "Delegate liefert Ergebnis: {0}", result );
    	}
    }
    

    Interessant ist dabei, das die Callback-Methode "ResultsReturned" zum Abfangen der Ergebnisse automatisch aufgerufen wird, so bald die delegierte Methoden ein Ergebnis zurückliefert. Wie kann man so was

    del.BeginInvoke( new AsyncCallback( ResultsReturned ),del);
    

    in C++ schreiben?



  • Hast Du's schon probiert?
    Zeige mal deine Versuche...
    Simon



  • Du rufst es damit nicht _asynchron_ auf, sondern _synchron_!





  • Jochen Kalmbach schrieb:

    Du rufst es damit nicht _asynchron_ auf, sondern _synchron_!

    In der MSDN-Dokumentation steht eindeutig, dass BeginInvoke
    ein Delegaten asynchron für den Thread ausführt , in dem das dem Steuerelement zugrunde liegende Handle erstellt wurde:

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

    Darüber hinaus habe ich das Beispiel auf die Asynchronität getestet. Funktioniert wirklich.



  • simon.gysi schrieb:

    @martin_pavel:
    http://msdn.microsoft.com/en-us/library/2e08f6yc.aspx

    Danke für den Link. Dieses Beispiel ist aber für Microsoft Visual Studio 2008/.NET Framework 3.5. Momentan arbeite ich mit MVS2005/.NET Framework 2.0.



  • simon.gysi schrieb:

    Hast Du's schon probiert?
    Zeige mal deine Versuche...
    Simon

    Du wolltest meine Versuche haben. Das ist ein davon:

    public delegate void ControlValueChangedDelegate (double value);
    
    public ref class MyControl : public System::Windows::Forms::UserControl
    {
    
    private: double m_ValueCur;
    
    public: ControlValueChangedDelegate^ EvEditWheelValueChanged;	
    
    private: void SetValueInControl ()
    	 {
    		//this->EvEditWheelValueChanged (m_ValueCur);
    
    		// benachrichtigen, dass der Wert geändert wurde
    		if (this->EvEditWheelValueChanged != nullptr)
    		{
    			for each (ControlValueChangedDelegate^ del in this->EvEditWheelValueChanged->GetInvocationList())
    				System::IAsyncResult^ result = this->BeginInvoke (del, m_ValueCur);
    
    			// hier muss man sich noch um den Aufruf von EndInvoke() kümmern !!!
    		}
         }
    }
    

    Ich habe echt keine Ahnung, wie man hier ein AsyncCallback Delegate aufrufen kann. Die Funktion Control::BeginInvoke hat die folgende Überladungsliste:
    Control.BeginInvoke (Delegate)
    Control.BeginInvoke (Delegate, Object[])



  • Ich verstehe dein Problem nicht. Es ist exakt die gleiche Weise wie bei C#.
    Wo hängst Du genau fest?
    Beim instantieren des AsyncCallback's?



  • simon.gysi schrieb:

    Ich verstehe dein Problem nicht. Es ist exakt die gleiche Weise wie bei C#.
    Wo hängst Du genau fest?
    Beim instantieren des AsyncCallback's?

    Du hast die Nadel auf den Kopf getroffen. Wo und Wie wird eine Instanz von AsyncCallback angelegt? In C# passiert das im Delegate. In C++ System::Delegate hat keine BeginInvoke Methode. 👎



  • #include "stdafx.h"
    
    using namespace System;
    using namespace System::Threading;
    
    public delegate void AsyncMethodCaller();
    
    public ref class A
    {
    public:
    	void func()
    	{
    		Console::WriteLine(L">>> A::func() called; Thread ID " + Thread::CurrentThread->ManagedThreadId);
    	}
    
    	void endfunc(IAsyncResult^ ar)
    	{
    		AsyncMethodCaller^ d = safe_cast<AsyncMethodCaller^>(ar->AsyncState);
    		d->EndInvoke(ar);
    
    		Console::WriteLine(L">>> A::endfunc() called; Thread ID " + Thread::CurrentThread->ManagedThreadId);
    	}
    };
    
    int main(array<System::String ^> ^args)
    {
    	Console::WriteLine(L">>> main(..) called; Thread ID " + Thread::CurrentThread->ManagedThreadId);
    
    	A^ a = gcnew A();
    
    	AsyncMethodCaller^ d = gcnew AsyncMethodCaller(a, &A::func);
    	d->BeginInvoke(gcnew AsyncCallback(a, &A::endfunc), d);
    
    	Console::ReadKey();
        return 0;
    }
    

    BeginInvoke(..) und EndInvoke(..) erscheint nicht in der IntelliSense Auswahl... :-))
    Simon



  • simon.gysi schrieb:

    #include "stdafx.h"
    
    using namespace System;
    using namespace System::Threading;
    
    public delegate void AsyncMethodCaller();
    
    public ref class A
    {
    public:
    	void func()
    	{
    		Console::WriteLine(L">>> A::func() called; Thread ID " + Thread::CurrentThread->ManagedThreadId);
    	}
    
    	void endfunc(IAsyncResult^ ar)
    	{
    		AsyncMethodCaller^ d = safe_cast<AsyncMethodCaller^>(ar->AsyncState);
    		d->EndInvoke(ar);
    
    		Console::WriteLine(L">>> A::endfunc() called; Thread ID " + Thread::CurrentThread->ManagedThreadId);
    	}
    };
    
    int main(array<System::String ^> ^args)
    {
    	Console::WriteLine(L">>> main(..) called; Thread ID " + Thread::CurrentThread->ManagedThreadId);
    
    	A^ a = gcnew A();
    
    	AsyncMethodCaller^ d = gcnew AsyncMethodCaller(a, &A::func);
    	d->BeginInvoke(gcnew AsyncCallback(a, &A::endfunc), d);
    
    	Console::ReadKey();
        return 0;
    }
    

    BeginInvoke(..) und EndInvoke(..) erscheint nicht in der IntelliSense Auswahl... :-))
    Simon

    Das habe ich gerade auch erfahren.Die beiden Methoden erscheinen soger in der MSDN-Hilfe nicht. Das ist ja echt blöd! 😡
    Dafür gibt es aber noch bessere Vorgehensweise, und zwar mit BackgroundWorker! 👍



  • So einfach geht das nicht... um irgendwas wieder "synchron" zu machen, muss man jemanden haben, der dies macht (siehe: ISynchronizeInvoke)! Das gibt es im .NET Framework nur bei "Windows-Forms" (Control) und im WPF-Umfeld (SynchronizationContext).

    Einfach "so" etwas versuchen wollen zu "synchronisieren", was gar nicht vorhanden ist, geht halt nicht...



  • Jochen Kalmbach schrieb:

    So einfach geht das nicht... um irgendwas wieder "synchron" zu machen, muss man jemanden haben, der dies macht (siehe: ISynchronizeInvoke)! Das gibt es im .NET Framework nur bei "Windows-Forms" (Control) und im WPF-Umfeld (SynchronizationContext).

    Einfach "so" etwas versuchen wollen zu "synchronisieren", was gar nicht vorhanden ist, geht halt nicht...

    Verstehe deine Aufregung nicht. 🕶



  • Verstehe mich gerade auch nicht 😕


Anmelden zum Antworten