Thread an einem bestimmten Punkt anhalten um Daten zu übergeben



  • Hallo zusammen

    Vielleicht kann mir hier jemand bei diesem Problem weiter helfen. Ich habe eine Anwendung in visual c++ .net.

    Neben der Progrthread läuft eine weitere Thread in einer while-Schleife. Für die Thread habe ich eine eigene Klasse namens CMYThreads angelegt.

    void CMyThreads::MyThreadProc()
    {
    	while (1==1)
    	{
    	     ProcessIO();
    	     Thread::Sleep(20);
           }
    }
    

    Von Zeit zu Zeit erhält die Hautpanwendung über das Netz Daten, die zu verarbeiten sind. Zu diesem Zweck sollte sich der Programmzeiger in der Thread sich nicht in der Routine ProcessIO befinden. Anschliessend sollte die Thread weiter arbeiten.

    Wie könnte man das bitte elegant/einfach lösen?

    Vielen Dank für Eure Hinweise

    Geri
    Vielleicht kennt einer von Euch auch ein gutes Tutorial in dem die Thread-Verabeitung VC++ .net und das zu Grunde liegende Konezpt beschrieben ist. Schadet bekanntlich ja nie, etwas Background zu haben.



  • Dieser Thread wurde von Moderator/in evilissimo aus dem Forum C++ in das Forum C# und .NET verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • du könntest eines der win32 synchronisationsobjekte nehmen (events z.b.). wenn deine ProcessIO() nicht rumidlen muss dann etwa sowas in der art

    void ThreadProc(void)
    {
       while (1)
       {
           if (WaitForSingleObject(data_avalable_event, INFINITE) == WAIT_OBJECT_0)
           {
              ProcessIO();
              SetEvent (data_processed_event);
           }
       }
    }
    


  • Sleep-Schleifen sind die n00b-Lösung. Wenn du deinen Thread auf ein bestimmtes Ereignis warten lassen willst, dann benutze einen Monitor. Wenn du den Zugriff auf eine Resource regeln willst, benutze ein Semaphor. Zu deiner I/O-Geschichte kann ich nichts sagen, da ich die Umstände nicht kenne (z.B. ob die I/O Operationen blockierend sind).



  • Hallo

    Vielen Dank für Euer rasches Feedback!

    Bitte entschuldigt. Ich habe es nicht ganz klar ausgedrückt.

    Das Program sollte folgendermassen funktionieren. In der Programm-Hauptthread gibt es eine TCP-Komponente, die ein onReceive-Ereignis auslöst, wenn neue Daten vom Netz kommen.

    Parallal dazu läuft ein zweiter Thread (er hat immer etwas zu tun), z.B

    void CMyThreads::MyThreadProc()
    {
        while (1=)
        {
    
    // hier sollte, wenn neue Daten vorhanden sind, die Routine ProcessNewInData ausgeführt werden
    // ansonsten fahre mit DoCalculation fort.
            ??
             for (int i=0; i<1000; i++)
             {
                DoCalulation(); // hiess vorher unglücklicherweise ProcessIO();
             }
             Thread::Sleep(20);
           }
    } 
    
    void CMyThreads::ProcessNewInData(System::Byte buffer[], System::Int32 DataLen
    {
      // verarbeite die neuen Daten
    }
    

    Wenn nun aber neue Daten da sind, dann sollten die neuen Daten z.B. in einer Routine Names ProcessNewInData(inbuffer,datalen) gleich danach verarbeitet werden, wenn sich der Programmzeiger ausserhalb von DoCalculation(); befindet - also an einer Stelle im While-Rumpf nur nicht in DoCalculation.

    Vielen Dank nochmals
    Geri



  • Du kannst selber entscheiden, wann deine Funktion aufgerufen wird - wenn du unbedingt außerhalb der DoCalculation sein muß, rufst du sie halt von außerhalb auf:

    CMyThread::MyThreadProc()
    {
      while(1)
      {
        if(/*Daten verfügbar*/)
          ProcessNewData();
        DoCalculation();
      }
    }
    


  • Hallo CStoll

    Vielen Dank für Deine Rückmeldung. Wie teile ich aber der Thread mit, dass neue Daten von der Main-Thread vorhanden sind und wie übergebe ich die Daten von der Main-Thread zur zweiten Thread (CMyThread)?

    Beste Grüsse
    Geri



  • Im einfachsten Fall bekommt der Hilfsthread beim Anlegen einen Pointer übergeben, an dem die notwendigen Informationen findet:

    struct data{...};//zu übergebende Daten
    typedef std::pair<bool,data> note_t;
    
    //im Hauptthread:
    note_t my_data;
    CMyThread* thrd=new CMyThread(&my_Data);
    ...
    my_data.second=/*neue Daten*/
    my_data.first=true;
    ...
    
    //Hilfsthread:
    CMyThread::CMyThread(note_t* data) : m_data(data) {}
    
    CMyThread::ThreadFunc()
    {
      while(1)
      {
        if(m_data->first)
        {
          //verarbeite m_data.second
          m_data.first=false;
        }
        ...
      }
    }
    

    (Alternativ könntest du auch Events zwischen den Threads hin und herschieben)

    PS: Das ist natürlich nur grob skizziert 😉



  • Geri schrieb:

    Hallo CStoll

    Vielen Dank für Deine Rückmeldung. Wie teile ich aber der Thread mit, dass neue Daten von der Main-Thread vorhanden sind und wie übergebe ich die Daten von der Main-Thread zur zweiten Thread (CMyThread)?

    Beste Grüsse
    Geri

    Wenn ein Thread dem anderen etwas mitzuteilen hat, ist ein Monitor oft gut. Der wartende Thread ruft am Monitor Wait() auf und dein Main-Thread kann ihn dann pulsen. Daten die auf dem Heap liegen, können alle Threads benutzen. Da du mindestens sowieso ein Objekt zum Waiten und Pulsen zwischen den beiden Threads teilst, kann dieses auch gleich noch die erforderlichen Daten halten.



  • Hallo CStoll und optimizer

    @CStoll
    Vielen Dank für Deinen Lösungsansatz! Wenn ich Deinen Code richtig verstehe, dann würdest du in der while-Schleife ein Flag abfragen und das Flag zurücksetzen, nachdem die Daten verarbeitet sind.
    Auf ähnliche Weise habe ich es auch schon gelöst. Jetzt wird es einigen s.w. die Haare aufstellen, eine
    bessere Lösung ist mir aber leider nicht eingefallen...

    // Epfangsroutine in der Hautpthread
    private: System::Void serverSocket1_OnReceive(System::Byte buffer[], System::Int32 DataLen, System::String *  remoteID)
    {	 
    	while (pMyThread->NewInputDataAvailable != 0) ; // warte bis MyThreadProce bereit ist	
    	pMyThread->WriteInputBuf(buffer,DataLen); // Übergebe die Daten
    	pMyThread->NewInputDataAvailable = 1; // signalisiere der Thread, dass neue daten da sind.
    }
    
    void CMyThreads::MyThreadProc()
    {
    	while (1)
    	{
    		if (NewInputDataAvailable != 0)  // prüfe ob neue Daten vorhanden sind
    		{
    			ProcessNewInputData(ThreadInBuffer,ThreadInBufferDataLen); // Verarbeite die neuen Daten			
    			NewInputDataAvailable = 0; // Signalisiere dem Hauptthread dass er bereit ist, neue Daten zu verarbeiten
    		}
                    for (int i = 0; i <1000; i++)
    		{
    		    DoCalculation();
    		}
                    Thread::Sleep(20);		
    	}
    }
    

    @optimizer
    Auch Dir vielen Dank! Mein Problem ist, dass die Methode DoCalculation(); immmer "laufen" sollte. Die einzige Ausnahme ist, wenn neue Daten von der Hauptthread vorhanden sind.
    Interessant is mit dem Monitor, nur umzusetzten komme ich das auf meinen Fall nicht 🙄 Irgendwie fehlt mir da noch der Durchblick. Ein Beispiel fand ich in der MSDN (Monitor.Enter-Methode).

    Beste Grüsse und ich hoffe, dass man ihr verstehen könnt was ich erreichen möchte und nochmals vielen Dank
    Geri



  • Ok, ich denke ich habe dich vorhin falsch verstanden. In deinem Fall geht es wahrscheinlich viel einfacher. Ist es nicht so, dass der Main-Thread einfach immer wieder den Rechen-Thread füttert, währenddessen der Rechen-Thread nicht auf bestimmte Objekte zugreifen soll?

    In diesem Fall brauchst du von Monitor eigentlich nur Enter() und Exit(). Jeder Thread, der auf einem Objekt was machen will, sollte vorher Monitor.Enter() aufrufen. Nur ein Thread kann den Monitor eines Objekts gleichzeitig betreten. Wenn neue Daten ankommen, muss dein Main-Thread einfach nur versuchen, den Monitor zu betreten. Sobald das erfolgreich war, kann er die neuen Daten reinschaufeln und den Monitor wieder verlassen. Dein Rechen-Thread sollte immer prüfen, ob der Main-Thread den Monitor betreten möchte (einfach ne Variable, die sich das merkt, verwenden) und den Monitor in diesem Fall verlassen und neu betreten. Das neu betreten klappt dann erst wieder, wenn der Main-Thread den Monitor verlassen hat, also fertig ist. 🙂

    In C# gibt es das lock-Statement, was das ganze so weit verbirgt, dass man die Monitor-Klasse gar nicht mehr im Code benutzt. Man schreibt einfach

    lock( myObject ) {
        ... // was mit myObject machen, nur ein Thread kann gleichzeitig myObject locken
    }
    

    Vielleicht gibt es dazu in C++.Net auch ein Äquivalent.


Anmelden zum Antworten