Threads und this_thread::sleeep_for



  • Hallo zusammen,

    ich habe folgende Aufgabe zu meinem Buch versucht:

    "Write a program with two threads: one that writes hello every second and one that
    writes world! every second"

    Meine bisherige Lösung:

    #include <iostream>
    #include <chrono>
    #include <thread>
    
    void hello()
    {
        std::cout << "Hello\n";
    }
    
    void world()
    {
        std::cout << "World\n";
    }
    
    int main()
    {
        std::thread t1{hello};
        std::thread t2{world};
    
        //while (true)
        //{
            t1.join();
            //std::this_thread::sleep_for(std::chrono::seconds(1));
            t2.join();
        //}
        return 0;
    }
    

    Ich bekomme aber einen std::system_error -> what(): Invalid Argument

    ich weiß im Prinzip halt nicht, wie ich dieses je eine Sekunde schlafen anwenden muss, ist mir aus dem Buch nicht ersichtlich.

    Code Beispiel aus dem Buch:

    using namespace std::chrono;
    
    auto t0 = high_resolution_clock::now();
    this_thread::sleep_for(milliseconds{20});
    auto t1 = high_resolution_clock::now();
    cout << duration_cast<nanonseconds>(t1 - t0).count() << " nanoseconds passed\n";
    

    habe schon bemerkt, dass es an dem thread.join() innerhalb der while(true) Schleife liegt. Weiß aber nicht, wie ich es sonst mehrmals ausgeben lassen soll

    Hoffe ihr könnt mir helfen (bzw. tut es, können bestimmt^^)

    LG
    HarteWare



  • Ist die Idee nicht, innerhalb der Threads eine Schleife zu haben und zu schlafen? Nachdem du die Threads startest, hast du ja in main() keine direkte Kontrolle mehr über ihren Programmablauf.

    Und musst du das synchronisieren, sodass "Hello" ständig vor "World" ausgegeben wird?



  • @Nexus
    Das ist wirklich die ganze Aufgabenstellung gewesen, also ist da wohl Spielraum für Interpretation. Bei meinem PC funktionierts ohne jegliche explizite Syncronisation, sprich es erscheint immer 'Hello' for 'World', also kann ich mir das Arbeiten mit mutex und lock erstmal ersparen, oder was man da halt so benötigen würde.

    Jedenfalls ist mir mein Hauptdenkfehler jetzt bewusst geworden, und es funktioniert wie es soll, danke 😉

    Falls es jemanden kümmert, so siehts jetzt aus:

    #include <iostream>
    #include <chrono>
    #include <thread>
    
    void hello()
    {
        while(true)
        {
            std::cout << "Hello ";
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
    
    void world()
    {
        while(true)
        {
            std::cout << "World!\n";
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
    
    int main()
    {
        std::thread t1{hello};
        std::thread t2{world};
    
        t1.join();
        t2.join();
    
        return 0;
    }
    


  • HarteWare schrieb:

    Bei meinem PC funktionierts ohne jegliche explizite Syncronisation

    Dir sollte klar sein, dass das nur zufällig gut geht. Minimale Änderungen (zum Beispiel dass ein Flash-Video im Hintergrund läuft) können dir alles kaputt machen. Wahrscheinlich war der Sinn der Aufgabe, dass du siehst, dass manchmal "Hello" vor "World" kommt und manchmal andersrum, als Motivation wozu man Mutexe braucht.



  • Ja, is mir klar. Nur so nebenbei, wäre es so richtig? Was wäre die "optimale Lösung"? Für so ein kleines Programm sollte es eine geben, oder?

    #include <iostream>
    #include <chrono>
    #include <thread>
    #include <mutex>
    
    std::mutex m;
    
    void hello()
    {
        while(true)
        {
            std::unique_lock<std::mutex> lck{m};
            std::cout << "Hello ";
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
    
    void world()
    {
        while(true)
        {
            std::unique_lock<std::mutex> lck{m};
            std::cout << "World!\n";
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
    
    int main()
    {
        std::thread t1{hello};
        std::thread t2{world};
    
        t1.join();
        t2.join();
    
        return 0;
    }
    


  • Der Lock nützt dir gar nichts. Er garantiert zwar, dass die Threads nicht gleichzeitig auf cout zugreifen können, aber nicht, dass hello vor world dran kommt. cout ist bereits threadsafe, daher hat selbst das keinen Effekt. Die Optimallösung hängt von den Anforderungen ab. Ich würde es optimal finden, wenn man die Threads weg lässt und jede Sekunde "Hello World" ausgibt. Dann kann garantiert nichts schief gehen. Ansonsten könnte man den Mutex in main locken, in world auch und in hello unlocken. Damit kann world nicht mehr vor hello dran kommen. Vorausgesetzt die sleep_for-Sache wird nie eine Sekunde driften. Um den Drift zu verhindern kannst du ihm sagen, dass er nicht eine Sekunde, sondern eine Sekunde minus Zeit der letzten Aktivierung schlafen soll. Aber ohne genauere Aufgabenstellung könnte ich nicht argumentieren welche Variante richtig wäre.



  • Nun gut, Aufgabenstellung ist wirklich exakt so (nur eine kleine Übung) : "Write a program with two threads: one that writes hello every second and one that
    writes world! every second"

    Also mit Threads, und ich denke alles weitere wäre "overkill", aber gut zu wissen, dass die locks so angewendet wenig Sinn machen, danke.

    LG



  • Dein Programm ist aber eines mit 3 Threads.



  • Lol, stimmt^^


Log in to reply