pThreads, Signals und Systemaufrufe



  • Hi leuz,
    ich stecke gerade etwas in der Zwickmuehle:

    Meine Applikation besteht aus mehreren Threads (pthreads).
    Diese Threads benutzen Systemfunktionen. Konkret z.B. "msgrcv" (Lesen
    einer Queue) oder auch Lesefunktionen fuer serielle Leitungen.

    Diese Systemfunktionen sollen jedoch nach einer gewissen Zeit
    abgebrochen werden. Dazu wird bekanntlich ein Timer aufgesetzt, welcher
    nach dieser Zeit SIGALRM ausloest und die Systemfunktion abbricht.

    Soweit so gut, leider gehoert SIGALRM aber nicht zu den synchronen Signals
    und kennt somit nur einen globalen (!) Signal-Handler.
    Nutzen also zwei parallele Threads Systemfunktionen mit Signal-Abbruch,
    bricht nur der Thread ab, welcher als letztes den Sigalarm-Handler
    aufgesetzt hat!

    Kennt jemand die Loesung fuer mein Problemchen?
    Wie kann ich z.B. in zwei Threads von zwei verschiedenen Seriellen Leitungen
    lesen und dabei aber nicht auf Timeouts verzichten?
    Polling moechte ich keins betreiben...

    Greets,
    dUKe

    PS.
    Kann sein dass sich da Linux und Solaris unterscheiden. Unter Solaris
    (meiner Zielplattform) erhalten threads keine eigene PID und somit auch keine
    eigene Signal-Handler (fuer asynchrone Signals).



  • Mit Polling wär es eigentlich leicht. Aber du könntest auch asynchronen IO nehmen, dh. du bekommst ein Signal, wenn die Daten gelesen wurden. Das Timeout realisierst du dann einfach mit nanosleep.

    Kann sein dass sich da Linux und Solaris unterscheiden. Unter Solaris
    (meiner Zielplattform) erhalten threads keine eigene PID und somit auch keine
    eigene Signal-Handler (fuer asynchrone Signals).

    Jo, Linux ist (war) da nicht ganz Posix konform. Aber mit den Kernel-Threads (2.6) ist das glaub ich anders



  • kingruedi schrieb:

    Mit Polling wär es eigentlich leicht. Aber du könntest auch asynchronen IO nehmen, dh. du bekommst ein Signal, wenn die Daten gelesen wurden. Das Timeout realisierst du dann einfach mit nanosleep.

    wusste ichs doch, ich haette keine Serielle Leitung als Beispiel nehmen sollen..
    Meine Anwendung ist das Auslesen der MSG-Queue.
    Die Anwendung MUSS SOFORT nachdem eine Meldung eingegangen ist, diese
    auslesen.
    Beim Polling geht das nicht, da in dieser Zeit (nanosleep) gleich mehrere
    Meldungen ankommen koennten.
    Also muss der Thread (welcher die entsprechende Queue behandelt) immer
    in der Lese-Funktion (msgrcv) stehen, um gleich bei Ankunft der MSG reagieren
    zu koennen.

    Hat man aber mehrere Threads die je eine eigene Queue behandeln, so ist genau
    dies nicht mehr moeglich...
    ....



  • naja, für Echtzeit Anforderungen ist Solaris doch eh nicht geeignet. Außerdem kannst du man: poll(2) bzw. man: select(2) auch auf nur einen Handle ansetzen. Dann solltest du keine großen Probleme haben



  • kingruedi schrieb:

    naja, für Echtzeit Anforderungen ist Solaris doch eh nicht
    geeignet.

    Ok ich hab mich mit "SOFORT" vielleicht ein wenig zu ungenau ausgedrueckt 😉
    .. eigentlich meinte ich damit nur dass der Thread Event-gesteuert reagieren
    soll und nicht via polling.

    kingruedi schrieb:

    Außerdem kannst du man: poll(2) bzw. man: select(2) auch auf nur einen Handle ansetzen. Dann solltest du keine großen Probleme haben

    Ich hab noch nie mit poll gearbeitet, aber laut der manpage werden keine
    IPC-Queues supportet..

    Aber vielleicht hab ichs auch ungenau oder zu kompliziert beschrieben:

    Thread 1                         Thread 2
    |while (1)--------------------|  |while (1)--------------------|  
    |  warte auf MSG (IPC-Box 1)  |  | warte auf MSG (IPC-Box 2)   |
    |    - bei Timout: mach was   |  |    - bei Timout: mach was   | 
    |    - sonst bearbeite MSG    |  |    - sonst bearbeite MSG    |
    |-----------------------------|  |-----------------------------|
    

    so, Problem : Timeout via Signal unmoeglich, da SIGALRM nur einen einzigen
    Sig-Handler kennt.
    - Kann ich Signals irgendwie Parameter mitgeben, um so unterscheiden zu
    koennen welcher Thread SIGALRM ausgeloest hat ?
    - Oder kann ich sonstwie Timeouts von Systemfunktionen setzen.. ?



  • Wenn du mit alarm() glücklich bist - mal abgesehen davon, dass SIGALARM für beide Threads gleich ist -, dann könntest du statt eines Threads ja auch einen eigenen Prozess mit fork() abspalten. Dann könnte es gehen.

    Martin



  • Mit fork könnte es natürlich gehen, aber dann müsste ich ne weitere
    IPC einrichten für den Datenaustausch zwischen Child-Prozess und Hauptprogramm...
    Mit Threads hingegen kann ich gemeinsame Ressourcen nutzten...

    wie auch immer.. ich glaube ich habe die Lösung:
    Ein dritter Thread erhält das Signal (SIGUSR1), mit der Thread-ID als
    Parameter (sigaction). So kann dieser "Signal-Handler-Thread" entscheiden,
    welcher Thread nun ein Timeout hat und diesem den SIGALRM senden (pthread_kill)
    was noch immer funktioniert...

    So.. für weitere Ideen bin ich offen, aber ansonsten komm ich (wieder) klar 😉



  • Solaris'dUKe schrieb:

    Mit Threads hingegen kann ich gemeinsame Ressourcen nutzten...

    Wieso benutzt du dann ne IPC-queue? Der Sinn dieses Teils besteht doch hauptsächlich darin, dass ich zwischen Prozessen, die nicht verwandt sind, kommunizieren kann, weil ich sie über den Schlüssel identifizieren kann.

    Auf Dein eigentliches Problem zurückzukommen. Ich bin mir nicht sicher und sitze hier gerade an der falschen Maschine um das ganze zu testen, aber probier mal folgendes als sighandler:

    void mySigHandler(int sig){
       pthread_kill(pthread_self(), sig);
    }
    

    Die Funktionsweise sollte klar sein. Sighandler einfach für SIGALRM registrieren. Dem Thread in welchem der Handler ausgeführt wird, wird dann das Signal geschickt.


Anmelden zum Antworten