Thread oder Prozess
-
Das kann man so pauschal nicht beantworten. Eine mögliche Antwort könnte auch heissen: "Weder noch!"
Du kannst doch mittels "poll" auf ein Zeichen und einen Timeout warten. Dann liesst Du das Zeichen oder beendest Deine Verbindung.
Ansonsten kannst Du natürlich auch mit einem Thread arbeiten, was ich auch machen würde, wenn die "poll"-Variante aus irgend welchen Gründen nicht anwendbar ist. Aber auch wenn Dir Threads rein theoretisch klar sind, so kann ich trotzdem nur vor den u.U. anfallenden Snychronisationsproblemen warnen - kommt halt drauf an, wie sehr Du mehrere Threads ineinander verzahnen musst.
Die schönste Variante (speziell unter Unix ähnlichen Betriebssystemen) ist natürlich die mit "fork". Damit kann man einen Großteil der Thread-Probleme ausschliessen, allerdings ist man auch sehr eingeschränkt. In Deinem Fall wüsste ich nicht, wie Du einfach so mit 2 Prozessen arbeiten willst. Der 2. Prozess(Timer) soll ja auf Deinen Vaterprozess einfluss nehmen, in dem er dazu veranlasst wird die Kommunikation abzubrechen. Das könntest Du z.B. dadurch erreichen, dass nach dem Timeout sich der 2 Prozess einfach beendet und Du auf das Signal in Deinem Signal-Handler entsprechend reagierst. Auf der anderen Seite muss allerdings auch Dein Vaterprozess den Timer des 2. Prozesses jedes mal resetten, wenn Du doch vor Eintreten des Timeouts ein Zeichen gelesen hast. Hier wird es schon etwas schwieriger. Insgesamt müssen also diese beiden Prozesse miteinander kommunizieren, z.B. via MessagePassing, SharedMemory, ... -> Stichwort IPC (Inter Process Communication).
Ich würde also erst einmal schauen, ob es nicht mit einem Thread/Prozess funktioniert, und wenn nicht, halte ich Threads (allerdings ohne Dein Programm zu kennen) für geeigneter als Prozesse.
-
Ja.... jetzt mal noch eine Rückfrage:
Ist sowas Sache des Schnittstellentreibers oder meiner Applikation?
Gruß und nochmals Danke
-
Du bekommst nur das Signal von der Schnittstelle, was du daraus machst und wie ist deine Aufgabe.
-
Jaja, das Signal,
aber was steht da drin? Momentan lese ich mit read() einzelne Bytes aus. Aber wie kann ich prüfen, wann die ankamen?
Gruß
-
Aber wie kann ich prüfen, wann die ankamen?
Es gibt wohl keine andere Methode als dass dein Programm auf die ankommenden Daten wartet und selbst misst wieviel Zeit vergangen ist, seit die letzten Daten angekommen sind.
Muss während gewartet wird noch etwas anderes gemacht werden ?
Wenn nicht, kannst du einfach mit select(...)(oder auch poll(..)) auf das ankommende Byte warten, und ein Timeout setzen.Kommt innerhalb der eingestellten Zeit kein Byte an liefer select(..) -1.
Wenn ja, kannst du das gleiche tun nur dass select(...) und der restliche Code der die Daten empfängt, in einen extra Thread wandern.
-
Hallo und danke für die Antwort,
Es muss, während gewartet wird, noch was weiteres gemacht werden.
Eigentlich brauche ich zwei Zeiten:Ich möchte ein Busprotokoll umsetzen. Dabei gibt es folgende Vorgaben:
Mit dem Empfang eines Bytes müssen beide Timer auf Null gesetzt und gestartet werden. Der erste Timer prüft, ob der Intervall zwischen zwei Bytes eines Nachrichtenrahmens eine gewisse Zeit (z.B. 1,5ms) nicht überschreitet.
In der Busspezifikation ist vorgegeben, daß zwei Rahmen auch einen gewissen zeitlichen Abstand (z.B. 4,5ms) haben müssen. Diese Zeit muss der zweite Timer überprüfen.
Der zweite Timer muss deswegen mit Empfang jedes Bytes auf Null gesetzt werden, weil jedes Byte das letzte sein könnte.Also:
Beide Timer müssen laufen und gleichzeitig sollen weitere Bytes von der seriellen Schnittstelle gelesen werden.Für den ersten Timer könnte ich mir eine Lösung vorstellen, in dem ich die Schnittstelle in den kanonischen Modus setze, wobei die Flags MIN == 0 und TIME > 0 in der Struktur TERMIOS eingestellt sind.
"In diesem Fall wird zu Beginn der Leseoperation die Zeitschaltuhr gestartet. Die Leseoperation kehrt hier zurück, wenn entweder 1 Byte gelesen oder die mit TIME eingestellte Zeitschaltuhr abgelaufen ist (z.B. 1,5ms). Dies bedeutet, daß entweder das gelesene oder kein Byte zurückgegeben wird."Müsste klappen, oder? Aber was mache ich mit dem 2. Timer? Hat da jemand eine weitere Idee (außer Thread / Prozess?)
Herzlichen Dank
-
Also während gewartet wird, mussen zwar 2 Timer laufen aber sonst muss nichts abgearbeitet werden, richtig ? Das würde einiges erleichtern.
Für den ersten Timer könnte ich mir eine Lösung vorstellen, in dem ich die Schnittstelle in den kanonischen Modus setze, wobei die Flags MIN == 0 und TIME > 0 in der Struktur TERMIOS eingestellt sind.
OK. Es kann funktionieren, aber ich persönlich habe es immer so gelösst:
unsigned char reciv_byte(fd) { unsigned char reciv_byte=0; struct timeval timeout; fd_set fdset; timeout.tv_sec=0; timeout.tv_usec=1500;//1500µs warten FD_ZERO(fdset); FD_SET(fd, fdset); if (select(fd+1, &fdset, NULL, NULL, &timeout)== -1) {perror("select() failed");} else { if (FD_ISSET(fd, &fdset)) { if (read(fd,&reciv_byte,1) == -1) { perror("read() failed"); } } else { perror("FD_ISSET failed"); } } return reciv_byte; }
Müsste klappen, oder? Aber was mache ich mit dem 2. Timer? Hat da jemand eine weitere Idee (außer Thread / Prozess?)
Eine einfache Lösung wäre hier einfach GTimer zu benutzen:
#include <glib.h> int main (int argc,char **argv) { unsigned long elapsed_us; GTimer *timer1=g_timer_new(); GTimer *timer2=g_timer_new(); g_timer_start(timer1); usleep(1500); g_timer_stop(timer1); g_timer_elapsed(timer1,(unsigned long*)&elapsed_us); printf("elapsed_us:%lu\n",elapsed_us); g_timer_reset(timer1); g_timer_destroy(timer1); g_timer_destroy(timer2); return 0; }
So. Das wäre mein Vorschlag.
-
Hm, also den ersten Vorschlag kann ich nachvollziehen. Allerdings kann ich nicht abschätzen, was die bessere Möglichkeit ist: Deine oder meine. Im Prinzip machen ja beide das Gleiche, oder?
Bei der zweiten Möglichkeit habe ich ein paar Probleme. Ich finde in meinem Buch nichts über GTimer. Auch geht bei mir kein
man: gtimer
Allerdings nutze ich auch Red Hat 8.0Ist DAS das Problem?
Gruß und Danke
-
Deine Timing-Werte sind im unteren Millisekunden-Bereich.
Probier mal die Funktion gettimeofday(), die liefert den Wert des System-Timers bis auf die Mikrosekunde genau (falls vom System unterstuetzt).
Um die Zeitintervalle zu messen, merkst Du Dir den ersten und den zweiten Wert, den gettimeofday() zurueckliefert, und subtrahierst dann, um das Ergebnis herauszubekommen.
#include <sys/time.h> typedef unsigned long long timestamp_t; timestamp_t gettimestamp( void ) { struct timeval tv; timestamp_t ts; gettimeofday( &tv, 0 ); ts = (timestamp_t) tv.tv_sec * 1000000ULL + (timestamp_t) tv.tv_usec; return ts; } void func( void ) { timestamp_t ts1, ts2, diff; ts1 = gettimestamp(); ... ts2 = gettimestamp(); diff = ts2 - ts1; /* Differenz in Mikrosekunden */ }
-
Hallo Danke für Eure Beiträge,
ich bin dem Vorschlag von Marcin (mit dem select()-Befehl) gefolgt und habe jetzt ein paar Tests gemacht.
Ich muss aber eine Zeit von 520µs erkennen können. Der kleinste Zeitintervall, denn die select()-Funktion erkennt, ist (zumindest auf meinem System) 1,953ms (was ziemlich genau 1/512 ist).
Wenn ich also 520µs messen will, erhalte ich 0s. Kann man das irgendwie umstellen? Woran könnte das liegen?
Viele Grüße,
yecc
-
nichts über GTimer
Ich meinte auch GTimer
glib , noch nie gehört ?
Egal. Du kannst auch den Timer so realisieren wie es Power Off gepostet hat.
Beide Timer sind praktisch auf gut 10µs genau, wenn nicht besser.Wenn ich also 520µs messen will, erhalte ich 0s. Kann man das irgendwie umstellen? Woran könnte das liegen?
Also bei mir liegt die Genauigkeit bei select() so im Bereich +/-2ms, ich weiss es leider nicht woran das liegt.
Ich weiss nicht welche Baudrate du benutzt aber bei z.B 19200 dauert das Üertragen eines Bytes schon 500µs.
-
yecc schrieb:
Ich muss aber eine Zeit von 520µs erkennen können. Der kleinste Zeitintervall, denn die select()-Funktion erkennt, ist (zumindest auf meinem System) 1,953ms (was ziemlich genau 1/512 ist).
Wie hast Du die Zeit "1,953ms" gemessen?
Manche Systemaufrufe wie poll() und select() koennen nur im ms-Bereich warten.
Es ist dann besser, die I/O Handles auf Nonblocking zu schalten und mit einer anderen Methode zu warten.
Mit gettimeofday() solltest Du relative genaue Zeitwerte bekommen. Mit nanosleep() kannst Du kleinere Warteintervalle machen (wenn's ueberhaupt geht).
Denk dran, dass bei UNIX frueher das Warten im Sekundenbereich gang und gaebe war.
(d.h. die feiner aufgeloesten Wartefunktion haben ihren Weg erst in den 90ern nach UNIX gefunden, und Linux ist sowieso spaeter erst entwickelt worden; aber bei AIX und Solaris kann es einige Probleme in der Richtung geben; vielleicht heutzutage nicht mehr)
-
Hallo,
wie ich die Zeit gemessen habe?
Ich habe Zeichen aus einer seriellen Schnittstelle ausgelesen an die ein anderer PC Daten mit 1200 Baud gesendet hat (bei 9600 Baud konnte ich nichts messen).
Nach der Zeitmessung von 5000 eintreffenden bytes und einer Häufigkeitsverteilung der gemessenen Werte ist es möglich, eine
minimale Zeitdifferenz zu erkennen. Diese beträgt 0,001953~s und entspricht damit ungefähr 1/256 einer Sekunde.
Größere Zeitdifferenzen entsprechen auffallend genau ganzzahligen Vielfachen von 0,001953~s, so dass ich angenommen habe, dass es sich bei diesem Wert um den kleinsten vom Linux Kernel messbaren Zeitintervall handelt.Viele Grüße
-
Ich meinte, welche Systemroutine Du dafuer aufgerufen hast.
-
Folgenden Code habe ich benutzt...:
FILE *fp; fp = fopen("statistic.txt", "a"); for(count = 0;count < 5000; count++) { FD_ZERO(&read_fds); FD_SET(IInterface, &read_fds); timeout.tv_sec = 2; timeout.tv_usec = 0; a = select(IInterface + 1, &read_fds, NULL, NULL, &timeout); fprintf(fp,"%d,%d\n", (int) timeout.tv_sec, (int) timeout.tv_usec); VSlvRead(&UCChar1); } fclose(fp);
-
Wobei:
void VSlvRead(unsigned char *UCPChar) { read(IInterface, UCPChar, 1); }
-
Hier ein Auszug aus der Select-Manpage:
man 2 select schrieb:
On Linux, the function select modifies timeout to reflect the amount of time not slept;
D.h. nach dem Aufruf von select() enthaelt die timeval-Struktur die Zeit, die nicht geschlafen wurde.
-
Hallo,
ja, das ist klar. Ich habe natürlich dann die Zeit in timeval von 2 Sekunden abgezogen (später in der Auswertung dann...)
Gruß und Danke