laufendes C-Programm befehle geben

Gast #4792797
Lesenswert?

Hallo,

ich suche nach einer Möglichkeit einen laufenden C-Programm befehle über 
die Comandline zu geben.

Ich arbeite auf einen PI3 mit Raspbian Jessy

ich habe ein kleines C-Programm welches "ständig" für node den Status 
von ADCs und einigen GPIOs auszulesen (über I2C).
jetzt möchte ich das Tool so erweitern, dass ich dem zwischendurch 
befehle geben kann <- ohne dass diese pausiert...

ein paar Ideen hatte ich z.B. mit Dateien welche ständig ausgelesen 
werden oder mit einer Datenbank welche abgearbeitet werden... aber 
irgendwie habe ich das Gefühl, dass es sich negativ an der Zeit 
auswirkt.

Folgendes Problem, wenn ich ein 2. Programmchen starte welches GPIOs 
schaltet, kommt dieses MANCHMAL durcheinander... immer wenn das Lese C 
mit dem Schreib C "gleichzeitig" arbeitet, schaltet er falsch...

Hat jemand eine Idee was ich machen könnte?
=> Ich brauche entweder die möglichkeit, möglichst schnell mit einem 
Tool STÄNDIG lesen und gleichzeitig zwischendurch schreiben, oder statt 
schreiben das lesetool kurzzeitig pausieren <- was mir fast noch lieber 
wäre!

Vielen Dank
#4792813
Lesenswert?

baer schrieb:
> ich suche nach einer Möglichkeit einen laufenden C-Programm befehle über
> die Comandline zu geben.

Beschissene Idee, denn dafür würde man echte IPC brauchen. Die Command 
Line laufender Prozesse lässt sich AFAIK nach dem Start nicht mehr 
ändern.

Normalerweise macht man dann ein Config File und einen Signal Handler 
für das USR1 Signal, dass das Programm anweist seine Config neu 
einzulesen. Das ist deutlich einfacher zu programmieren.
Gast #4792861
Lesenswert?

baer schrieb:
> ein paar Ideen hatte ich z.B. mit Dateien welche ständig ausgelesen

Dazu wurden named pipes erfunden. Minimalbeispiel:
1
#include <fcntl.h>
2
#include <stdio.h>
3
#include <sys/stat.h>
4
#include <unistd.h>
5

6
int main(void)
7
{
8
    int fd;
9
    const char* myfifo = "/tmp/myfifo";
10
    char buf;
11
    
12
    mkfifo(myfifo, 0666);
13
    fd = open(myfifo, O_RDONLY);
14
    while(1)
15
    {
16
        // falls etwas in die named pipe geschrieben wurde:
17
        if (read(fd, &buf, 1) > 0) // normalerweise würde man mehr als ein zeichen lesen
18
        {
19
            switch(buf)
20
            {
21
            case 'q':
22
                goto exit_loop;
23
            case 's':
24
                fprintf(stderr, "befehl=s\n");
25
                break;
26
            default:
27
                fprintf(stderr, "unbekannt: %c\n", buf);
28
                break;
29
            }
30
        }
31

32
        // normaler ablauf:
33
        fprintf(stderr, "Temperatur = 17 Grad\t");
34
        fprintf(stderr, "Wasserstand = 23 m\n");
35
        sleep(1);
36
    }
37

38
exit_loop:
39
    close(fd);
40
    unlink(myfifo);
41
    return 0;
42
}

Jetzt kann man mit
1
echo "q" > /tmp/myfifo
oder einem aufwändigeren Programm Dinge in die named pipe schreiben, die 
dann im obigen Beispiel auftauchen. Im Beispiel ist ein Bug, der die 
Endlosschleife erst startet, wenn ein Zeichen in die named pipe 
geschrieben wurde.

> irgendwie habe ich das Gefühl, dass es sich negativ an der Zeit
> auswirkt.
Solche low-level-Unix-Fileoperationen sind nicht mit dem Öffnen einer 
Word-Datei vergleichbar ;).
Gast #4792862
Lesenswert?

Möglichkeiten gibt es viele:z.B. Programm bleibt im Vordergrund und man 
macht eine Schleife die die Eingaben abfragt (und die eigentliche 
Aufgabe in einem extra Thread). Dabei kann man z.B. mit ncurses 
arbeiten, damit kann man auch komplette Textmenüs u.ä. erzeugen, aber 
auch so einfache Dinge wie bleib in einer Zeile während der Eingabe und 
lösche sie wieder. Oder man macht zwei Programm die z.B. Netzwerkports 
kommunizieren. Eines läuft permanent und das andere führt man nur mit 
dem entsprechenden Parameter aus und dieser wird dann an das 
Hauptprogramm weitergegeben.
#4792997
Lesenswert?

Tom schrieb:

>
> int main(void)
> {
>     int fd;
>     const char* myfifo = "/tmp/myfifo";
>     char buf;
>
>     mkfifo(myfifo, 0666);
>     fd = open(myfifo, O_RDONLY);
>     while(1)
>     {
>         // falls etwas in die named pipe geschrieben wurde:
>         if (read(fd, &buf, 1) > 0) // normalerweise würde man mehr als
> ein zeichen lesen
>         {
>             switch(buf)
>             {
>             case 'q':
...
> }
> [/c]
>
> Jetzt kann man mit
>
1
echo "q" > /tmp/myfifo
> oder einem aufwändigeren Programm Dinge in die named pipe schreiben

Das obige Programm ist leider falsch, weil der einzige Thread durch 
einen blockierenden Systemcall wie read() blockiert wird, und daher 
nichts anderes machen kann. Man muss je blockierenden filedescriptor 
einen eigene thread starten. D.h. einen ggf. für die "normale" Arbeit 
und einen Thread, um von der command-pipe/socket zu lesen. Die 
Synchronisation der Datenstrukturen, die gemeinsam verwendet werden, 
darf man dann natürlich auch nicht vergessen. Oder man versetzt den fd 
in den non-blocking-mode und macht ein polling, was aber eigentlich 
nicht schön ist.
Also besser, je blockierendem fd einen eigenen thread mit pthread_create 
starten... nicht schwer, aber man muss eben einige Grundprinzipien 
beachten.
#4793010
Lesenswert?

Sende den Befehl in eine Datei (z.B. .txt) unter einem vorher 
definierten Namen und Verzeichnis. Sperren bzw. warten falls bereits 
existent.
Frage im Programm nach dieser Datei; existiert diese Lese sie; lösche 
sie; kümmre Dich um den Inhalt.

Das Gleiche kann man mit einem Eintrag in der INI machen.

Sinnvollerweise sollte das Programm, bei seinem Start, einen eventuellen 
Eintrag bzw. eine existente Datei, löschen.
#4793051
Lesenswert?

Es geht, ich habe mehrere Hintergrundprogramme (Dämone), die das können.
Ganz simpel ist es allerdings nicht. Wenn das Programm im Hintergrund 
läuft, kann man über dasselbe Programm Einstellungen des laufenden 
Dämons abfragen oder auch ändern.

Dafür gibt es MessageQeues, eine Form von Interprozesskommunikation. 
Wenn das Programm gestartet wird, informiert es sich, ob schon eine 
Instanz am Laufen ist. Wenn ja, geht es nicht in den Hintergrund, 
sondern kommuniziert mit dem laufenden Dämon.
Gast #4793106
Lesenswert?

baer schrieb:
> ich habe ein kleines C-Programm welches "ständig" für node den Status
> von ADCs und einigen GPIOs auszulesen (über I2C).
> jetzt möchte ich das Tool so erweitern, dass ich dem zwischendurch
> befehle geben kann <- ohne dass diese pausiert...

Ein select mit einem Timeout auf stdin. Kommt der Timeout, dann messen, 
sonst input bearbeiten

MfG Klaus
#4793125
Lesenswert?

Ein select oder poll mit timeout oder auch eine periodische 
Unterbrechung mittels eines Signals (alarm) für zu einer polling 
Strategie: das ist nicht gut.

Entweder sind alle DatenQuellen Dateideskriptoren, dann kann man 
erfolgreich mit select / poll ein Multiplexen über die blockierenden 
Quellen machen.

Ist aber eine Quelle keine fd, dann braucht man mehrere Threads.

Meistens führen Programme mit mehreren Threads zu strukturell 
einfacheren Programmen.

Man kann die Threads auch auf mehrere Prozesse aufteilen: dann braucht 
man allerdings IPC-Mechnismen (semaphores / mutex, message-queues / 
pipes, shared memory) für den Datenaustausch.

Ein gutes Buch zu der Thematik ist der Klassiker:

APUE:
https://www.amazon.de/Programming-Environment-Addison-Wesley-Professional-Computing/dp/0321637739
#4793148
Lesenswert?

Wilhelm M. schrieb:
> Aber jetzt wiederholen sich die Antworten ... (s.o.)

Ups. Ich hätte vielleicht die Seite vor dem Antworten nochmal neu laden 
sollen.

Wilhelm M. schrieb:
> Ein select oder poll mit timeout oder auch eine periodische
> Unterbrechung mittels eines Signals (alarm) für zu einer polling
> Strategie: das ist nicht gut.

Wenn er sowieso regelmäßig seinen ADC einliest, passt das doch. Ob er 
nun in einem Thread regelmäßig seine Messung macht und dann mit 
irgendeinem nanosleep oder so wartet und in einem separaten Thread dann 
auf das File wartet oder select() nutzt, um beides zu machen, ist doch 
Jacke wie Hose.

> Ist aber eine Quelle keine fd, dann braucht man mehrere Threads.

Auch dann geht's ohne. Schau dir z.B. an, was die Eventloops von 
modernen GUI-Frameworks so alles ohne Threads machen können.

> Meistens führen Programme mit mehreren Threads zu strukturell
> einfacheren Programmen.

Kommt sehr drauf an. Man muss sich dann um Synchronisation kümmern und 
kann sich auch schnell mal einen fiesen Fehler einfangen, der schwer zu 
finden ist. Meines Erachtens machen Threads die Programme oft genug eher 
komplizierter als einfacherer - zumindest wenn sie auch miteinander 
kommunizieren sollen. Deshalb gehe ich damit eher sparsam um und 
vermeide sie, wenn sie nicht nötig sind.

> Man kann die Threads auch auf mehrere Prozesse aufteilen: dann braucht
> man allerdings IPC-Mechnismen (semaphores / mutex, message-queues /
> pipes, shared memory) für den Datenaustausch.

Dafür hat er ja dann gleich das, was er ursprünglich mal wollte: Das 
Programm von außen steuern.
#4793155
Lesenswert?

Rolf M. schrieb:
>
> Wenn er sowieso regelmäßig seinen ADC einliest, passt das doch. Ob er
> nun in einem Thread regelmäßig seine Messung macht und dann mit
> irgendeinem nanosleep oder so wartet und in einem separaten Thread dann
> auf das File wartet oder select() nutzt, um beides zu machen, ist doch
> Jacke wie Hose.

Ich habe gesagt, wenn er blockierende (!) systemcalls zum Lesen seiner 
Daten verwendet! Dann nützt ihm ein select() nichts, wenn er sein device 
nicht als filedescriptor abstrahiert hat. Wenn ja, ist ein multiplexen 
mit select() ok (s.o.)
#4793157
Lesenswert?

Rolf M. schrieb:

>> Meistens führen Programme mit mehreren Threads zu strukturell
>> einfacheren Programmen.
>
> Kommt sehr drauf an. Man muss sich dann um Synchronisation kümmern und
> kann sich auch schnell mal einen fiesen Fehler einfangen, der schwer zu
> finden ist. Meines Erachtens machen Threads die Programme oft genug eher
> komplizierter als einfacherer - zumindest wenn sie auch miteinander
> kommunizieren sollen. Deshalb gehe ich damit eher sparsam um und
> vermeide sie, wenn sie nicht nötig sind.

Gemeint war: strukturell.

Natürlich braucht man Synchronisation (s.o.!), und auch diesen 
Werkzeugkasten sollte man beherrschen. Aber auch hier gilt m.E.: wenn 
man die Grundprinzipien kann, ist es nicht so schwer. Und Fehler: ja, 
die kann man überall machen.
#4793169
Lesenswert?

Wilhelm M. schrieb:
> Ich habe gesagt, wenn er blockierende (!) systemcalls zum Lesen seiner
> Daten verwendet!

Wie kommst du darauf, dass er solche hat? Und welche Systemcalls könnten 
das denn sein, um Daten einzulesen, aber nicht von einem Filedeskriptor? 
Mir würde da keiner einfallen.
Probleme sehe ich eher, wenn der Filedeskriptor und sein ganzes Handling 
hinter einer API versteckt und nicht zugänglich ist. Dann ist man ggf. 
gezwungen, auf Threads auszuweichen.

Wilhelm M. schrieb:
> Natürlich braucht man Synchronisation (s.o.!), und auch diesen
> Werkzeugkasten sollte man beherrschen. Aber auch hier gilt m.E.: wenn
> man die Grundprinzipien kann, ist es nicht so schwer. Und Fehler: ja,
> die kann man überall machen.

Ich muss mir ja nicht ohne Not zusätzliche potenzielle Fehlerquellen 
einbauen.
#4793174
Lesenswert?

Rolf M. schrieb:
> Wilhelm M. schrieb:
>> Ich habe gesagt, wenn er blockierende (!) systemcalls zum Lesen seiner
>> Daten verwendet!
>
> Wie kommst du darauf, dass er solche hat? Und welche Systemcalls könnten
> das denn sein, um Daten einzulesen, aber nicht von einem Filedeskriptor?
> Mir würde da keiner einfallen.

Ich weiß ja nun nicht, was der TO hat ...

Beispiel aus einer anderen Ecke, die mir sofort einfällt: mq_receive()
Gast #4793237
Lesenswert?

ööhhhhhh,

erstmal 10000 Dank für die Millionen Antworten ;)
es freut mich wenn einem Freundlich geholfen wird, ist heute keine 
Selbstverständlichkeit mehr.

joa, ich bin da eher "einsteiger" im Gebiet. Aber die idee mit der Datei 
hatte ich auch...

also mach ich das so
1
while(1) {
2

3
datei lesen (in welcher ggf. Steuerbefehle sind)
4
=> wenn Steuerbefehle dann diese abarbeiten
5

6
adc & gpios einlesen
7

8
kurze pause einlegen
9

10
}

das Problem was hierbei entsteht ist, dass ich hier eine Datei ja im 
falle eines Falles gleichzeitig lesen und beschreiben muss... geht das 
"so einfach"

ich habe oben was von "Polling" gelesen, soweit ich weiß, geht das, dass 
man die Datei nur zum lesen öffnet und jemand anderes nur zum schreiben.

leider habe ich die Erfahrung gemacht, das Konzepte (die man falsch 
angeht) ggf. sehr lange funktionieren... und in einem "ungünstigen" 
Moment bekommt man dann Fehler.

Vielen Dank
#4793249
Lesenswert?

baer schrieb:
>
> also mach ich das so
>
>
1
while(1) {
2
> 
3
> datei lesen (in welcher ggf. Steuerbefehle sind)
4
> => wenn Steuerbefehle dann diese abarbeiten
5
> 
6
> adc & gpios einlesen
7
> 
8
> kurze pause einlegen
9
> 
10
> }
>

Ich nehme mal jetzt an, dass adc und gpio einlesen nicht blockierend 
sind (unter blockierenden Systemcalls versteht man solche, bei denen man 
keine Obergrenze an Ausführungszeit angeben kann).

1) das Lesen der Datei und das Beschreiben durch ein anderes Programm 
ist nicht grundsätzlich falsch, produziert hier jedoch eine 
race-condition (Wettlaufsituation): die Datei ist eine gemeinsame 
Ressource, die von zwei Threads bearbeitet wird. Hier muss man 
Massnahmen ergreifen.

2) kurze Pause einlegen: der Thread blockiert und kann die Datei nicht 
neu lesen. Je nachdem was erwartet wird, kann das zu unerwünschtem 
Verhalten führen (weil ja das Steuerkommando nicht sofort bearbeitet 
wird).
Gast #4793379
Lesenswert?

> Ich nehme mal jetzt an, dass adc und gpio einlesen nicht blockierend
> sind (unter blockierenden Systemcalls versteht man solche, bei denen man
> keine Obergrenze an Ausführungszeit angeben kann).

ja, das sind zwei unterschiedliche über i2c angebundene module...

> 1) das Lesen der Datei und das Beschreiben durch ein anderes Programm
> ist nicht grundsätzlich falsch, produziert hier jedoch eine
> race-condition (Wettlaufsituation): die Datei ist eine gemeinsame
> Ressource, die von zwei Threads bearbeitet wird. Hier muss man
> Massnahmen ergreifen.

was mir noch eingefallen ist, ich muss ja noch irgendwie verhindern, 
dass ein befehl "mehrfach" ausgeführt wird :/ d.h. ich müsste doch die 
Datei "nochmals" beschreiben!?!? oder hat da jemand ne bessere idee?

> 2) kurze Pause einlegen: der Thread blockiert und kann die Datei nicht
> neu lesen. Je nachdem was erwartet wird, kann das zu unerwünschtem
> Verhalten führen (weil ja das Steuerkommando nicht sofort bearbeitet
> wird).

naja mit kurz mein ich,... meine GPIO schaffen nur alle ~50ms gelesen zu 
werden! also hab ich ne Pause von 150ms eingelegt um hier nicht 
falschwerte zu erhalten... diese Latenz ist noch in Ordnung für die 
ausgabe

man könnte auch
1
long leseAbtand = 150 //ms
2

3
while(0) {
4

5
datei lesen
6
wenn datei steuerbefhel {
7
  steuerbefehl abarbeiten
8
  ***
9
}
10

11
wenn lasttime + leseAbtand < now {
12
  long lastTime = now()
13
  lese gpio & adc
14
}
15

16
}

*** die frage ist jetzt nur, wie kann ich jetzt die Steuerbefehl Datei 
leeren?
Gast #4793404
Lesenswert?

@Oliver S.
öh nein... so ist es nicht dass mir das nicht gefällt...

ich dachte, das ist genau das.

und die erste "Lösung" die ich finde:
http://www.gnu.org/software/libc/manual/html_node/Creating-a-Pipe.html

macht auch nichts anderes als eine Datei schreiben oder lesen!?
=> wo ich trotzdem dran hänge, dass ich ein tool habe das befüllt
und ein 2. tool habe das liest und leert!? <- geht das?

die idee mit dem 2. thread gefällt mir...
aber wie schaut das "konkret" aus?
> stdin ...
Gast #4793408
Lesenswert?

Wilhelm M. schrieb:
> Genaues Lesen: das gilt nur auf Linux!!!!

Das habe ich und bin einfach mal davon ausgegangen, dass der TE auf 
seinem RPI nicht so viele verschiedene Unix-Derivate laufen lassen will, 
so wie du einfach mal davon ausgegangen bist, dass er zum Auslesen der 
Hardware Message-Queues verwenden will.
Ich war zugegebenermaßen etwas überrascht, dass das in POSIX nicht als 
filedescriptor festgelegt ist, denn der Charme ist ja eigentlich gerade, 
dass man praktisch alle Kommunikationskanäle mit select() nutzen kann.

baer schrieb:
> joa, ich bin da eher "einsteiger" im Gebiet. Aber die idee mit der Datei
> hatte ich auch...
>
> also mach ich das so
> while(1) {
>
> datei lesen (in welcher ggf. Steuerbefehle sind)
> => wenn Steuerbefehle dann diese abarbeiten
>
> adc & gpios einlesen
>
> kurze pause einlegen
>
> }
> das Problem was hierbei entsteht ist, dass ich hier eine Datei ja im
> falle eines Falles gleichzeitig lesen und beschreiben muss... geht das
> "so einfach"

Für sowas drängen sich pipes geradezu auf. Die kannst du zur 
Kommunikation zwischen Programnen nutzen und Daten da reinschreiben und 
rauslesen wie bei Dateien, aber ohne den Umweg über eine echte Datei zu 
gehen. Der eine schreibt einfach immer rein, und beim anderen kommt es 
genau so wieder an. Was rausgelesen wurde, ist automatisch auch weg, und 
wenn nichts reingeschrieben wird, gibt's auch nix zu lesen.
Im einfachsten Fall kann dein Programm sogar von stdin lesen, und du 
kannst die Pipe von außen verbinden. Wenn du auf der Shell sowas 
schreibst wie:
1
ls | grep "hallo"

ist das nämlich nichts anderes als das Verbinden der Standardausgabe von 
ls mit der Standardeingabe von grep über eine pipe.
Alternativ kann man eine pipe auch einfach in der Kommandozeile mit 
mkfifo erzeugen. Dann bekommt sie einen Namen, über den man sie sogar 
wie eine Datei öffnen kann.
#4793517
Lesenswert?

Rolf Magnus schrieb:
> Wilhelm M. schrieb:
>> Genaues Lesen: das gilt nur auf Linux!!!!
>
> Das habe ich und bin einfach mal davon ausgegangen, dass der TE auf
> seinem RPI nicht so viele verschiedene Unix-Derivate laufen lassen will,
> so wie du einfach mal davon ausgegangen bist, dass er zum Auslesen der
> Hardware Message-Queues verwenden will.

Das Problem dabei ist ja bei solchen Dingen, also einen mqd_t als int 
als filedescriptor zu benutzen, dass dann auf Linux funktioniert, und 
dann gegebenenfalls als source irgendwoanders hin übernommen wird. Und 
schon haben wir das Problem. Deswegen empfehle ich das niemals.
#4793523
Lesenswert?

Rolf Magnus schrieb:

> ist das nämlich nichts anderes als das Verbinden der Standardausgabe von
> ls mit der Standardeingabe von grep über eine pipe.
> Alternativ kann man eine pipe auch einfach in der Kommandozeile mit
> mkfifo erzeugen. Dann bekommt sie einen Namen, über den man sie sogar
> wie eine Datei öffnen kann.

(Eine unnamed-pipe geht nur mit verwandten Prozessen: pipe())

Also ein named-pipe! Die kann man selbst im Programm per systemcall 
mkfifo erstellen. Der CommandProzess öffnet die dann wie eine Datei und 
schreibt sein Kommando da rein. Zudem könnte man die named-pipe aka fifo 
auch per socat oder ähnlichem im Netzwerk bekannt machen. Auch ganz 
hübsch.

Trotzdem: ich würde den Kommandoteil und den Meßwert-Verarbeitungsteil 
in unterschiedliche Threads packen. Aber - wie schon gesagt - wenn Du 
mit der Verzögerung über dein sleep() / nanosleep() leben kannst, dann 
brauchst Du das natürlich nicht ...
Gast #4793556
Lesenswert?

Hallo, ich benutze für solche Aufgaben einen Namedpipe-Server z.B. mit 
Winform GUI und der Nampedpipeclient ist ein Consolenprogramm, welches 
über ein Protokoll Daten an den Server sendet. Der Server beantwortet in 
meinem Protokoll die Befehle etc und zeigt dann die Daten grafisch an, 
funktioniert seit Monaten ohne Probleme.
Gast #4793562
Lesenswert?

Das könnte man gut über ein Terminalserver machen, das heisst Dein 
Programm implementiert eine kleine Konsole. Dann kannst Du über

telnet localhost <Dein Port e.g. 16100>

verbinden und die Kommandos übergeben. Das ganze läuft dann in einem 
eigenen Thread.

Grüsse,
René
Gast #4793670
Lesenswert?

Wilhelm M. schrieb:
>> Alternativ kann man eine pipe auch einfach in der Kommandozeile mit
>> mkfifo erzeugen. Dann bekommt sie einen Namen, über den man sie sogar
>> wie eine Datei öffnen kann.
>
> (Eine unnamed-pipe geht nur mit verwandten Prozessen: pipe())
>
> Also ein named-pipe!

Ja, natürlich. Was sonst stellst du dir unter einer Pipe mit einem Namen 
vor, als eine named pipe?

> Die kann man selbst im Programm per systemcall mkfifo erstellen.

Oder eben mit dem Kommandozeilentool mkfifo, das ja auch nix anderes 
macht.

> Trotzdem: ich würde den Kommandoteil und den Meßwert-Verarbeitungsteil
> in unterschiedliche Threads packen. Aber - wie schon gesagt - wenn Du
> mit der Verzögerung über dein sleep() / nanosleep() leben kannst, dann
> brauchst Du das natürlich nicht ...

Nun, wenn man sowieso eine zyklisch durchlaufene Hauptschleife braucht, 
warum nicht? Ich würde das aber eher mit clock_nanosleep() machen, da 
man dort auch absolute Zeiten angeben kann.
Offenbar macht der TE das Einlesen der Daten von seinen Schnittstellen 
ja sowieso schon nonblocking und zyklisch mit einer Timing-Steuerung. 
Dann kann man in der Schleife auch gleich das Kommando einlesen. Wozu 
dann extra in einem separaten Thread blockierend lesen und dann in einen 
anderen Thread weitergeben, der dann sowieso pollt? Einzig wenn die 
Auswertung der Befehle so exorbitant lange dauert, dass die Ausführung 
zu weit verzögert wird, wäre es sinnvoll, das in einen anderen Thread 
auszulagern und es damit zu entkoppeln.
#4793689
Lesenswert?

Rolf Magnus schrieb:

>
> Ja, natürlich. Was sonst stellst du dir unter einer Pipe mit einem Namen
> vor, als eine named pipe?

habe ich geschrieben, weil Dein Beispiel

ls | grep "hallo"

eine unnamed benutzt.

> Nun, wenn man sowieso eine zyklisch durchlaufene Hauptschleife braucht,
> warum nicht? Ich würde das aber eher mit clock_nanosleep() machen, da
> man dort auch absolute Zeiten angeben kann.

Mmh...absolut, also 11.11.16, 20:00:00. Nein, es ist immer eine 
Zeitspanne ...

> Offenbar macht der TE das Einlesen der Daten von seinen Schnittstellen
> ja sowieso schon nonblocking und zyklisch mit einer Timing-Steuerung.

Mag sein, dass das non-blocking geschieht.

Dreht man allerdings an der Verzögerungsszeit, beeinflusst man damit 
implizit die längste Antwortzeit auf ein Kommando. Das(!) finde ich halt 
unschön.
Gast #4794056
Lesenswert?

Hallo,

leider find ich online nicht das richtige HowTo oder ich stell mich zu 
sehr an...

hat jemand evtl. eine kurze Beschreibung zur Hand wie ich das mit der 
"pipe" hinbekomme

eigentlich will ich zuerst einfach mal ein tool, dass in einer Instanz 
"dauerläuft" und in der 2. Instanz will ich befehle eingeben

also hab ich 2x Putty offen... im einen fenster läuft ./pipeTest
1
int main(int argc, char **argv){
2
  FILE *stream;
3
  int file, c;
4
  
5
  stream = fdopen (file, "r");
6
  
7
  while(1) {
8
    
9
    c = fgetc (stream);  
10
    printf( "%i \n", c );
11
    
12
  }
13

14
  return(0);
15
}

zwar ist das Programm ein "dauerläufer"

aber auf ein
> ls | grep 2
in einer anderen Puttyinstanz reagiert er nicht :/

wo sind meine Denkfehler?

Danke
#4794101
Lesenswert?

Wilhelm M. schrieb:
>> Nun, wenn man sowieso eine zyklisch durchlaufene Hauptschleife braucht,
>> warum nicht? Ich würde das aber eher mit clock_nanosleep() machen, da
>> man dort auch absolute Zeiten angeben kann.
>
> Mmh...absolut, also 11.11.16, 20:00:00. Nein, es ist immer eine
> Zeitspanne ...

Es ist eine Zeitspanne, aber diese sollte exakt mit Ende der letzten 
Zeitspanne beginnen und nicht mit Aufruf von nanosleep(). Das heißt, ich 
lese einmal die Uhrzeit aus, sage dann, der nächste Zyklus soll zu 
dieser Zeit + x starten. Und dann addiere ich für jeden Zyklus immer die 
gewünschte Zykluszeit drauf. So bekomme ich für eine gewünschte 
Zykluszeit von x immer sehr genau alle x einen Zyklus und nicht erst 
immer nach x + y für y = (ggf. variable) Laufzeit meiner Zyklusfunktion. 
Voraussetzung ist natürlich, dass diese Funktion selbst nicht länger 
braucht als x.
#4794139
Lesenswert?

baer schrieb:
> hat jemand evtl. eine kurze Beschreibung zur Hand wie ich das mit der
> "pipe" hinbekomme
>
> eigentlich will ich zuerst einfach mal ein tool, dass in einer Instanz
> "dauerläuft" und in der 2. Instanz will ich befehle eingeben
>
> also hab ich 2x Putty offen...

Du musst entsprechend den obigen Antworten unterscheiden zwischen einer 
named pipe und einer ... pipe ohne Namen. Letztere kannst du nur von 
einem Prozess an einen anderen vererben, wenn du per fork() einen neuen 
Prozess startest. Das kannst du aber dann nicht von deinen zwei 
Putty-Fenstern aus machen.
Die named pipe dagegen hat einen Namen im Dateisystem, wie eine reguläre 
Datei, und die kannst du in deinem Programm auch wie eine aufmachen. 
Einmal nur zum lesen, das andere mal nur zum schreiben.
Siehe mkfifo. Der Einfachheit halber kannst du das mal einfach auf der 
Konsole aufrufen:
1
mkfifo /tmp/meinfifo

ein
1
 ls -l /tmp

sollte dann in etwa sowas zeigen:
1
prw-rw-r-- 1 rolf  rolf    0 Nov 15 20:38 meinfifo

Das p ganz am Anfang steht für pipe. Die öffnest du dann in deinem 
Programm einfach wie eine reguläre Datei zum lesen, und dann kannst du 
z.B. mit
1
echo "Hallo" > /tmp/meinfifo

etwas reinschreiben, das von deinem Programm dann wieder rausgelesen 
werden
kann.

Zu deinem Programm:

> int main(int argc, char **argv){
>   FILE *stream;
>   int file, c;
>
>   stream = fdopen (file, "r");

Wie kommst du auf fdopen(), noch dazu mit einem uninitialisierten 
Filedeskriptor? fdopen() macht was ganz anderes, als du offenbar denkst.

Wilhelm M. schrieb:
> Mir ist schon klar was clock_nanosleep() macht: nur hatte ich schlicht
> nur nanosleep() in Deinem Post gelesen ... das habe ich aber auch
> korrigiert (s.o.)

Ja Himmel... liegt das an meinem Browser, dass ich alte Antworten immer 
erst nach dem Posten sehe? Ich vergess doch nicht jedesmal, den 
Update-Knopf zu drücken...
Sorry.
Gast #4795399
Lesenswert?

Frage...

warum hängt das Programm bis zur "ersten" Eingabe*???
1
  int fd, i;
2
  const char* myfifo = "myfifo";
3
  char buf[64];
4
  mkfifo(myfifo, 0666);
5
  fd = open(myfifo, O_RDONLY);
6
  while(1)
7
  {
8

9
    if ( (i = read( fd, buf, 64 )) > 0 ) {
10
      
11
      buf[i] = '\0';
12
      fprintf(stderr, "Ausgabe: %s", buf);
13
      
14
    }
15

16
//hier ist noch mehr
17

18
  return 0;
19
  }

wenn ich das Programm starte macht er erstmal NICHTS!!!

"hier ist noch mehr", *wird erst angesprochen sobald ich etwas in das 
Programm schicke => also echo "ein befehl" > myfifo
das funktioniert auch super! Aber irgendwie WILL er zuerst dass die 
"Datei" erzeugt wird oder ... was auch immer...

hat da jemand eine Idee?
#4795570
Lesenswert?

Du liest blockierend, d.h. read() wartet so lange, bis Daten aus der 
Pipe kommen. Deshalb geht's natürlich erst weiter, wenn was gelesen 
wurde. Du musst die Pipe non-blocking öffnen.
1
    fd = open(myfifo, O_RDONLY | O_NONBLOCK);

Übrigens hat dein Programm einen buffer-overflow-error. Mal sehen, ob du 
ihn selber findest. ;-)
#4795706
Lesenswert?

Tom schrieb:
> Rolf M. schrieb:
>> Du liest blockierend, d.h. read() wartet so lange, bis Daten aus der
>> Pipe kommen.
>
> Interessant wäre, warum es nach der ersten Eingabe auch ohne O_NONBLOCK
> geht und nichtblockierend einfach 0 Byte liest.

Weil dein Programm ein EOF bekommt, wenn der Schreiber seine Seite 
schließt. Das heißt, dass read() 0 zurückliefert und immer wieder sofort 
zurückkehrt, bis jemand die andere Seite der Pipe wieder öffnet.
#4795717
Lesenswert?

Pipes modellieren einen protokoll-losen Datenstrom. Da es kein Protokoll 
gibt und auch keine Möglichkeit, out-of-band-data zu übertragen, muss es 
eine andere Möglichkeit geben, das Kommunikationsende anzuzeigen. Dies 
geschieht dadurch, dass der Schreiber die Pipe schließt: dann kehrt beim 
Leser read() mit 0 zurück (also kein Fehler und keine Nutzdaten). Will 
der Leser die Kommunikation beenden und schließt die Pipe, so bekommt 
der Schreiber beim nächsten write() in die Pipe ein Signal SIG_PIPE 
(default action ist Programmabbruch) und (falls das Signal behandelt 
oder ignoeriert wird) kehrt write() mit Fehler EPIPE zurück.

(Gemeint ist der jeweils letzte Leser oder Schreiber: es kann ja mehrere 
geben)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren