sleep aus C++11 auf Windows zu ungenau



  • Hallo! Erstmal vorab: Ich schreibe diesen Thread im C++11 Forum, da ich mein Problem gerne nur dem C++ Standard lösen würde.
    Ich hab ein Programm geschrieben, welches UDP packets über das Netzwerk versendet (mit SFML, falls es jemanden interessiert 🙂 ).
    Diese Packets sind 512 byte groß und ich würde gerne die Übertragungsgeschwindigkeit einstellen können. Für eine Übertragungsgeschwindigkeit von 8 Mbit/s müssen zwischen zwei sends ca. 0,5ms vergehen. Natürlich ist das Verschicken von UDP packets nicht Teil des Standards, aber ich wollte euch nur etwas Kontext geben.
    Zu meinem Problem: Im Moment benutze ich std::this_tread::sleep_for(std::chrono::microseconds(500)). Allerdings hat man unter Windows nur eine Auflösung von 1ms, sodass mein Thread immer 1ms schläft.
    Gibt es im aktuellen Standard irgend eine Möglichkeit, mit der ich 2 Events (unter Windows) genauer als 1ms verzögern kann?



  • Genau garantiert wird dir da nichts, das ginge nur mit Echtzeitsystemen. Aber http://en.cppreference.com/w/cpp/thread/yield könnte für dich interessant sein.



  • Danke für deine schnelle Antwort!
    Ich habe es gerade mal ausprobiert:

    auto start = std::chrono::high_resolution_clock::now();
    std::chrono::microseconds us(250);
    auto end = start + us;
    do {
    	std::this_thread::yield();
    } while (std::chrono::high_resolution_clock::now() < end);
    
    end = std::chrono::high_resolution_clock::now();
    auto Diff = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
    std::cout<<Diff; //gibt 1000 aus (windows 7 64 bit)
    

    Hat also leider nichts gebracht. Wie timet man denn sowas wie Übertragungsspeed normalerweise?
    Ich würde ungern zwischen zwei sends irgendwelche dummy files auf die Festplatte schreiben, nur um etwas Zeit zu gewinnen 😃



  • Was hälst du denn davon, jede Millisekunde zwei Pakete zu schicken?



  • Oder z.B. zu messen, wieviel Zeit tatsächlich vergangen ist und dementsprechend viele Bytes zu schicken...



  • Michael E. schrieb:

    Was hälst du denn davon, jede Millisekunde zwei Pakete zu schicken?

    Oh man. An soetwas hatte ich garnicht gedacht 😃 Ich lasse jetzt nur alle X sends den thread sleepen und es funktioniert perfekt. Danke!

    dot schrieb:

    Oder z.B. zu messen, wieviel Zeit tatsächlich vergangen ist und dementsprechend viele Bytes zu schicken..

    Kann ich denn unter Windows (mit Standardmitteln) eine so genaue Zeitmessung machen? Die high_resolution_clock gibt mir auch nur ms Auflösung.



  • Es gibt die Multimedia Timer, die wohl besser auflösen. Habe selbst aber noch nicht damit gearbeitet.



  • Sleepy schrieb:

    dot schrieb:

    Oder z.B. zu messen, wieviel Zeit tatsächlich vergangen ist und dementsprechend viele Bytes zu schicken..

    Kann ich denn unter Windows (mit Standardmitteln) eine so genaue Zeitmessung machen? Die high_resolution_clock gibt mir auch nur ms Auflösung.

    Das liegt daran dass Microsoft offensichtlich nicht mal Kleinigkeiten korrekt implementiert bekommt. Nimm boost::chrono oder benutz ne andere Standardbibliothek falls möglich.
    Edit: Standardmittel ... ahjo. Ich sollte mehr lesen. Dann eben: http://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx



  • Anstatt in extrem kurzen Abständen wenige Bytes zu senden, kannst du aber auch einfach in längeren Abständen mehr Bytes senden, dann wird auch das Genauigkeitsproblem plötzlich verschwinden.

    Btw: sleep() ist rein konzeptionell schon nicht dazu gedacht "genau" zu sein...



  • Genau garantiert wird dir da nichts, das ginge nur mit Echtzeitsystemen

    Nicht mal mit Echtzeitsystemen, das liegt am Ethernet an sich.



  • Anderer Ansatz:

    Du legst ein Sendekontingent fest, das bei jedem Versenden eines Paketes um die Paketlänge verringert wird. Vor dem Versenden des Pakets prüfst du, ob dein Kontingent >= der Paketlänge ist, nur dann versendest du das Paket, ansonsten wartest du ein kurzes Intervall und erhöhst dein Sendekontingent um einen passenden Wert. Bei einem maximalen Datendurchsatz von 600 KiB/s könntest du jeweils 10 msec warten und dabei dein Kontingent um 10KiB erhöhen. Möglicherweise musst du deine Telegramme in Stücken versenden, weil sie größer als das Sendekontingent sind. Ist ein bisschen Fummelei mit Zeitstempeln um das Kontingent anzupassen, sollte aber eigentlich kein größeres Problem sein.
    Du solltest vielleicht nicht telegramm-orientiert denken, sondern traffic-orientiert.



  • Danke für eure Tipps!
    Im Moment benutze ich den einfachsten Ansatz: jede Millisekunde ein 1024 byte Paket verschicken. Damit erreiche ich einen Upload von ca. 8 Mbit/s (viel mehr ist bei mir auch garnicht drin 😃 ). Damit bin ich sehr zufrieden!


Anmelden zum Antworten