2016-08-09 86 views
2

zu verwenden Ich mache C-Programm in Linux. Ich habe einen Haupt-Thread, der ständig Werte von zwei Variablen aktualisiert, und ein anderer Thread schreibt diese Variablenwerte alle 20 Millisekunden in eine Datei. Ich habe usleep benutzt, um dieses Zeitintervall zu erreichen. Beispielcode ist unten.Ist es geeignet, usleep als Timer in c

main() 
{ 
. 
. 
. 
. 
. 

pthread_create(...write_file..); /* started another thread by passing a function write_file */ 
while(variable1) 
    { 
    updates value of variables 

    } 

return 0; 
} 


void write_file() 

{ 
. 
. 
. 
. 
fp = fopen("sample.txt" , "a"); 

while(variable2) 
{ 

    fprintf(fp," %d \n", somevariable); 

    usleep(20 * 1000); 

} 

fclose(fp); 
} 

Ist es geeignet zu verwenden usleep Funktion 20 Millisekunden Zeitintervall erreichen oder sollte ich einige andere Methoden wie Timer.? Ist das usleep genau genug? Beeinflusst diese Sleep-Funktion den Haupt-Thread?

+0

Zumindest können Sie die aktuelle Zeit mit 'gettimeofday' oder' clock_gettime' abrufen und nur die Zeit einplanen, die für die nächste Aktivität fehlt. – Marian

+0

C11-Entwurfsstandard n1570: * 5.1.2.4 Multi-Thread-Ausführungen und Datenrennen 4 Zwei Ausdrucksauswertungen stehen in Konflikt, wenn einer von ihnen einen Speicherort ändert und der andere den gleichen Speicherort liest oder ändert. 25 Die Ausführung eines Programms enthält ein Datenrennen, wenn es zwei widersprüchliche Aktionen in verschiedenen Threads enthält, von denen mindestens einer nicht atomar ist und keiner vor dem anderen auftritt. Ein solches Datenrennen führt zu undefiniertem Verhalten. * TL; DR: 'sleep()' ist keine Synchronisation. – EOF

Antwort

1

Die Verwendung der sleep() Familie führt oft zu einem nicht präzisen Timing, insbesondere wenn der Prozess viele CPU-konsumierende Threads hat und die erforderlichen Intervalle relativ klein sind, wie 20ms. Sie sollten also nicht davon ausgehen, dass der Aufruf *sleep() die Ausführung genau zur angegebenen Zeit blockiert. Für die oben beschriebene Situation kann die tatsächliche Schlafdauer sogar zweimal oder mehr größer als spezifiziert sein (unter der Annahme, dass der Kernel nicht in Echtzeit ist). Als Ergebnis sollten Sie eine Art von Kompensationslogik implementieren, die die Schlafdauer für nachfolgende Anrufe einstellt.

Genauer (aber natürlich nicht ideal) ist die Verwendung von POSIX-Timern. Siehe timer_create(). Die genauesten Timer sind diejenigen, die SIGEV_SIGNAL oder SIGEV_THREAD_ID Benachrichtigungen verwenden (letzteres ist nur auf Linux-Systemen).Als Signalnummer können Sie eines der Echtzeitsignale verwenden (SIGRTMIN bis SIGRTMAX), aber beachten Sie, dass pthread-Implementierungen oft nur wenige dieser Signale intern verwenden, daher sollten Sie die tatsächliche Zahl sorgfältig auswählen. Und auch etwas im Signal-Handler-Kontext zu tun erfordert besondere Aufmerksamkeit, da hier nicht jede Bibliotheksfunktion sicher verwendet werden kann. Sie können die sichere Liste here finden.

P.S. Beachten Sie auch, dass select(), die mit leeren Sätzen aufgerufen werden, eine ziemlich portable Möglichkeit zum Schlafen mit Sekundengenauigkeit ist.

2

Schlafen: sleep() und usleep()

Nun lassen Sie mich mit den leichten Timing Anrufen starten. Bei Verzögerungen von mehreren Sekunden ist es am besten, wenn Sie sleep() verwenden. Bei Verzögerungen von mindestens zehn Millisekunden (ungefähr 10 ms scheint die minimale Verzögerung zu sein) sollte usleep() funktionieren. Diese Funktionen geben der CPU andere Prozesse ("Ruhezustand"), so dass CPU-Zeit nicht verschwendet wird. Weitere Informationen finden Sie in den Handbuchseiten sleep (3) und usleep (3).

Bei Verzögerungen von weniger als 50 Millisekunden (abhängig von der Geschwindigkeit Ihres Prozessors und Ihrer Maschine sowie der Systemauslastung) dauert die Aufgabe der CPU zu viel Zeit, da der Linux-Scheduler (für die x86-Architektur) normalerweise benötigt mindestens etwa 10 bis 30 Millisekunden, bevor die Steuerung an Ihren Prozess zurückgegeben wird. Aus diesem Grund verzögert usleep (3) in kleinen Verzögerungen in der Regel etwas mehr als die Menge, die Sie in den Parametern angeben, und mindestens etwa 10 ms.

nanosleep()

In der 2.0.x-Reihe von Linux-Kernel gibt es einen neuen Systemaufruf, nanosleep() (siehe Nanosleep (2) -Manualseite), die Sie oder schlafen kann Verzögerung für kurze Zeiten (einige Mikrosekunden oder mehr).

Für Verzögerungen < = 2 ms, wenn (und nur wenn) Ihr Prozess auf weiche Echtzeitplanung eingestellt ist (mit sched_setscheduler()), verwendet nanosleep() eine Busy-Schleife; ansonsten schläft es, genau wie usleep().

Die Busy-Schleife verwendet udelay() (eine interne Kernel-Funktion, die von vielen Kernel-Treibern verwendet wird), und die Länge der Schleife wird mit dem BogoMips-Wert berechnet (die Geschwindigkeit dieser Art von Busy-Schleife ist eines der Dinge, die BogoMips misst genau). Siehe /usr/include/asm/delay.h) für Details wie es funktioniert.

Quelle: http://tldp.org/HOWTO/IO-Port-Programming-4.html

Ausprobieren Verwenden nanosleep() statt usleep(), sollte es für 20 ms Intervall genauer sein.