Forum: PC-Programmierung tcdrain() produziert endlosschleife unter linux


von Daniel (Gast)


Lesenswert?

Hallo,
ich weiß sehr wohl dass ihr mir direkt nur weiterhelfen könnt wenn ihr 
den Code seht.
Ich hoffe ihr könnt mir bei meiner Frage auch so weiterhelfen,
da es mehr um ein eingekreister Fehler geht.

Ich habe ein Programm,
dass mehrere Threads nutzt.
Von diesen Threads kann eine Funktion aufgerufen werden die über die 
serielle Schnittstelle Sachen versendet: SendCommand
1
void SendCommand(uchar adress, uchar command, uchar value) {
2
  uchar buffer[7];
3
4
  buffer[0] = adress | ADRESSBIT;
5
  buffer[1] = command & ~ADRESSBIT;
6
  buffer[2] = value & ~ADRESSBIT;
7
  //printTime();
8
  //printf("Serial.cpp-SendCommand:\t\tSchreibe Daten");
9
  //printf(" .");
10
  select(fd + 1, NULL, &wfds, NULL, NULL);
11
  //printf(".");
12
  //printf(".");
13
  if (FD_ISSET(fd, &wfds)) {
14
    pthread_mutex_lock(&serial_mutex);
15
    //printf(".");
16
    //usleep(500);
17
    write(fd, buffer, 3);
18
    //printf(".");
19
    tcdrain(fd);
20
    //printf(".");
21
    pthread_mutex_unlock(&serial_mutex);
22
    //printf(" fertig\n");
23
24
  }
25
  //else printf(" failed\n");
26
}
Ich hab diese mit Mutex abgesichert und so weiter. Funktioniert im 
Dauerbetrieb, 24h prima.

Damit das Programm dauernd läuft hab ich in der Main() eine 
Endlosschleife.
Die hat bisher nichts gemacht.

Jetzt fangen die Probleme an:
1
main() {
2
/* Initialisierung, Threadstarts */
3
while(1) {
4
SendCommand(TEMP_SENS_ADDR1, GET_TEMP, 0x01);
5
usleep(5000000);
6
}
7
return 1;
8
}
Stecke ich in die Endlosschleife der Main() Funktion eine regelmäßigen
Aufruf auf SendCommand, dann hängt irgendwann, nicht von Anfang an, 
tcdrain() in einer Endlosschleife und damit alles was auf Sendcommand 
beruht. Der Rest läuft weiterhin.

Jetzt meine Frage:
Was kann tcdrain in eine Endlosschleife bringen? Wo, und wie kann die
Fehlersuche am besten machen?

 Gruß Daniel

von Damian (Gast)


Lesenswert?

Hallo Daniel,

du schreibst nicht, wie fit du mit Threads bist und welche libc das ist.

Man muss für Multithreading ein Präprozessormakro beim compilieren 
setzen und kann nicht jede Libraryfunktion verwenden. Such mal in diesem 
PDF nach "thread".
http://www.gnu.org/software/libc/manual/pdf/libc.pdf

Gibt es Signalhandler? Da wird Locking zum Problem.



gruss
Damian

von Oliver R. (superberti)


Lesenswert?

Hi,

bist Du Dir sicher, dass Du tcdrain überhaupt benutzen kannst?

..."The fildes argument is an open file descriptor associated with a 
terminal. "

Ist das bei Dir der Fall? So wie ich das sehe, willst Du nur warten, bis 
write() fertig ist. Wenn Du synchron schreibst, dann ist das doch 
sowieso der Fall. Ich habe jedenfalls schon jede Menge serielle 
Kommunikation unter Linux gemacht, aber tcdrain war noch nie dabei...

Gruß, Oliver

von Daniel (Gast)


Lesenswert?

danke euch zwei.
Ich muss zugeben ich bin in threads nicht sehr bewandert, da ich aus der 
Hardware-Ecke komme. Ja es gibt Signalhandler, ich werde mal
mit euren Stichwörtern weitersuchen.

"fildes" ist bei mir ein geöffneter serieller Port.
Tcdrain() weglassen ist aber auch nicht die Lösung, da ja
irgendwas von mir programmiertes ja schon vorher im argen liegt,
es fällt halt hier auf.
Später kann ich es (wenn besser) auch weglassen :)

Danke!

 Daniel

von Daniel (Gast)


Lesenswert?

Achso, und ich nutze die Ubuntu/Eclipse/GCC Entwicklungsumgebung von 
atmel für den AVR32, Plattform NGW100.
Ich verlinke statisch um keine Probleme zu bekommen, das Filesystem
liegt auf SD-Karte, hat also genug freien Platz, es wird
aber im Filesystem auch nicht viel geschrieben.


Sry hatte ich ganz vergessen!

von Daniel (Gast)


Lesenswert?

ok, ich hab das Problem weiter eingekreist:
es scheint am Signal-Handling zu liegen.

Momentan hab ich zwei Funktionen, die auf SendCommand
zugreifen können:
- einmal ein Thread (Thread1), der über eine Funktion weckeThread
mit pthread_cond geweckt wird (es wird auch über mutex gelock, wie
es immer in Beispielcodes zu finden ist)
- einmal direkt aus der Endlosschleife in der main

Die Funktion weckeThread ist mit sigaction
dem SIGNAL SIG_USR1 zugewießen.

Kann das Probleme geben?
Ich weiß einfach nicht mehr weiter, ich würde das
Problem gerne verstehen, nicht nur irgendwie umprogrammieren.

In Kürze:
- periodisch:
Main()(endlos): wacht auf -> sendCommand()

- nicht-periodisch
SIG_USR1: weckeThread()->thread_condition
Thread1(endlos): wartet auf thread_condition -> sendCommand()

Gruß daniel

von Damian (Gast)


Lesenswert?

Hallo Daniel,

ein Thread, der auf einen Mutex wartet, kann von einem Signalhandler 
unterbrochen werden. Wenn du nun den selben Mutex im Signalhandler noch 
einmal lockst, fängt das Ganze an zu hängen, weil der selbe Thread 
praktisch 2 mal auf die Freigabe des Mutex wartet.

Lösung: Alle Signale am Anfang blocken und einen weiteren Thread 
aufmachen, den du dann mit sigwait() warten und die Arbeit des 
Signalhandlers machen lässt. Dort kann dann wieder fleissig auf den 
Mutex zugegriffen werden. Da der Thread ja aktiv mit sigwait() wartet, 
kann er auch nicht von einem Signal unterbrochen werden, was ja 
anscheinend die Ursache für dein Problem ist.

Da Threads auch nicht so mein täglich Brot sind, schau mal dort bim 
Unterpunkt Signalhandler rein:
http://www.linuxjournal.com/article/2121
ist zwar schon ziemlich alt, aber das Meiste trifft immernoch zu.

gruss Damian

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.