Funktionswarteschlange? Multitasking?



  • Diesmal habe ich eine komplexere Aufgabe:
    In meinem Programm wird eine Endlosschleife durchlaufen, bis das Programm endet(egal wie).

    1. Eine Funktion wird durch irgendein Event ausgeführt.

    2. Diese Funktion führt eine weitere aus und wartet, bis diese fertig ist.

    3. Die zweite Funktion stößt auf die Funktion "wait();".

    4. Der Rest der Funktion wird abgebrochen.

    5. Die erste Funktion wird wieder weiter ausgeführt, während die zweite Funktion erst weiter ausgeführt wird, wenn die Hauptschleife einmal weiter durchlaufen wurde.

    6. Die zweite Funktion wartet in einer Warteschleife von Funktionen, die in dem nächsten Durchlauf wieder weiter ausgeführt werden sollen. Also nicht von Anfang an, sondern von dem Punkt aus, an dem sie durch das "wait();" unterbrochen wurde.

    Ist das in C++ möglich? Durch Threading?

    MfG Raz



  • Klingt machbar ja.

    Klingt irgendwie sehr nach wait/signal (wait/notify):

    Liese sich auch mit Semaphoren erledigen, auch wenn du nicht direkt auf der Suche nach Synchronisationsmöglichkeiten bist (wird dann natürlich dennoch ein Thema werden).



  • Das Problem liegt ja daran, dass die erste Funktion nicht gestoppt werden darf, wenn die zweite Funktion wartet.

    EDIT: Und an Threading, hmm, ich weiss nicht ob ich daran will... 🙂



  • Du sagst ja, dass die erste Funktion eine weitere aufruft. Und diese wiederum meldet irgendwann, dass sie pausiert. Genau da sendest du eine Mitteilung, dass die erste Funktion weitermachen darf.

    function_2 ()
    {
     //..
     notify_1 (); // meldet function_1, dass es weitergeht
     wait_2 (); // wartet jetzt selbst
    }
    
    function_1 ()
    {
     function_2 ();
     wait_1 (); // wartet bis function_2 mitteilt
     //...
     notify_2 (); // wecke function_2 wieder auf; kannst du ich wo anders machen
    }
    

    Das ist so mit 2 (binären) Semaphoren ganz einfach gelöst.



  • Die Hauptschleife darf ja nicht durch ein wait(); unterbrochen werden.

    bool warte_auf_f1 == false;
    
    function warte_auf_was()
    {
    	while(warte_auf_f1 == false)
    	{
    		warte_einen_durchlauf(); // Warte einen Hauptloop Funktionsdurchlauf, ob F1 gedrückt wurde.
    	}
    }
    
    function warten_berechtigt()
    {
    	if(GetKeyState(VK_F1)) // Beispiel
    	{
    		warte_auf_f1 = true;
    	}
    }
    
    function hauptloop()
    {
    	warte_auf_was(); // Ein Funktionsaufruf. Beide loops sollen parallel ausgeführt werden, ohne dass der eine den anderen unterbricht.
    
    	while(true)
    	{
    		// Mache was...
    		// Dieser Loop darf nicht durch kein warte_einendurchlauf(); einer anderen Funktionen unterbrochen werden
    		warten_berechtigt();
    	}
    }
    


  • Wie wäre es damit, die Funktion ab dem wait() auszulagern und die Funktionszeiger darauf in eine std::queue zu packen? Der erste würde bei jedem Schleifendurchlauf aufgerufen werden, ist die Funktion fertig, wird sie wieder aus der Schlange genommen.
    So habe ich es zumindest gemacht (falls ich nichts durcheinander gebracht habe).
    Fertige Lösungen könnte es aber auch schon geben.



  • Ja, man könnte die Funktionen in einer Schlange abspeichern.

    #include "main.h"
    
    std::queue<void (*) ()> q;
    
    void wait(void (*func) ())
    {
    	q.push(func);
    }
    
    void test()
    {
    	// ...
    	std::cout << "Das sollte vor dem Warten kommen." << std::endl;
    
    	wait(test);
    
    	std::cout << "Das sollte nach dem Warten, einer Sekunde kommen." << std::endl;
    	// ...
    }
    
    int main()
    {
    	Sleep(2000);
    
    	test();
    
    	void (*func) ();
    	while(true)
    	{
    		Sleep(1000);
    
    		if(!q.empty())
    		{
    			func = q.front();
    			func(); // Das Problem ist, dass die Funktion immer wieder von vorne anfängt.
    			q.pop();
    		}
    	}
    
    	return 0;
    }
    

    Das Problem ist, dass die Funktion immer wieder von vorne anfängt, sonst würde sie sich nicht immer wieder in der Warteschlange eintragen.

    Was meintest du denn mit auslagern?



  • Ich meinte das so:

    #include <queue>
    
    std::queue<void (*) ()> q;
    
    void test_NachWarten();
    
    void wait(void (*func) ())
    {
        q.push(func);
    }
    
    void test()
    {
        std::cout << "Das sollte vor dem Warten kommen." << std::endl;
        wait(test_NachWarten);
    }
    
    void test_NachWarten()
    {
        std::cout << "Das sollte nach dem Warten, einer Sekunde kommen." << std::endl;
    }
    
    int main()
    {
        test();
        test();
        test();
        for(unsigned i = 0; i < 5; ++i)
        {
            if(!q.empty())
            {
                q.front()();
                q.pop();
            }
        }
        for(unsigned i = 0; i < 5; ++i)
        {
            test();
            if(!q.empty())
            {
                q.front()();
                q.pop();
            }
        }
        return 0;
    }
    

    Die Sleeps habe ich rausgenommen, codepad hätte es sonst nicht übersetzt.



  • Danke für das Beispiel.
    Ich probiere eine etwas handliche API aufzubauen. 🙂
    Und wenn man alles so machen muss, ist das nicht handlich :P.
    Wie soll denn das zB in while-Schleife gehen?
    Man müsste das in das Beispiel implementieren können, was ich ein paar Posts weiter oben geschrieben hab.
    Mit dem warten_berechtigt und einer endlosen Hauptschleife.



  • Hoert sich an wie kooperatives Multitasking mit yield oder aehnlichem ... und deine Warteschlange ist der Scheduler.


Anmelden zum Antworten