Wann immer man eine ereignisgesteuerte Architektur verwendet, muss man über einen einzigen Mechanismus verfügen, um den Abschluss eines Ereignisses zu melden. Wenn man unter Linux Dateien verwendet, muss man etwas aus der select- oder poll-Familie verwenden, was bedeutet, dass man bei der Verwendung einer Pipe feststeckt, um alle nicht dateibezogenen Ereignisse zu initiieren.
Bearbeiten :Linux hat eventfd und timerfd. Diese können Sie Ihrem epoll
hinzufügen Liste und verwendet, um aus der epoll_wait
auszubrechen wenn sie entweder von einem anderen Thread oder von einem Timer-Ereignis ausgelöst werden.
Es gibt eine andere Option und das sind Signale. Man kann fcntl
verwenden den Dateideskriptor so modifizieren, dass ein Signal ausgegeben wird, wenn der Dateideskriptor aktiv wird. Der Signal-Handler kann dann eine dateibereite Nachricht in jede Art von Warteschlange Ihrer Wahl schieben. Dies kann eine einfache Semaphor- oder Mutex/Condvar-gesteuerte Warteschlange sein. Da verwendet man nun select
nicht mehr /poll
, man muss keine Pipe mehr verwenden, um nicht dateibasierte Nachrichten in die Warteschlange zu stellen.
Gesundheitswarnung:Ich habe dies nicht ausprobiert und obwohl ich nicht sehen kann, warum es nicht funktionieren wird, kenne ich die Leistungsauswirkungen von signal
nicht wirklich Ansatz.
Bearbeiten:Das Manipulieren eines Mutex in einem Signalhandler ist wahrscheinlich eine sehr schlechte Idee.
Ich habe genau dieses Problem mit dem, was Sie erwähnen, gelöst, pipe() und libevent (das epoll umschließt). Der Worker-Thread schreibt ein Byte in seine Pipe FD, wenn seine Ausgangswarteschlange von leer auf nicht leer wechselt. Dadurch wird der Haupt-IO-Thread geweckt, der dann die Ausgabe des Worker-Threads abrufen kann. Das funktioniert großartig und ist eigentlich sehr einfach zu programmieren.
Sie haben das Linux-Tag, also werde ich das wegwerfen:POSIX-Nachrichtenwarteschlangen tun all dies, was Ihre "eingebaute" Anforderung erfüllen sollte, wenn nicht Ihren weniger erwünschten plattformübergreifenden Wunsch.
Die Thread-sichere Synchronisierung ist integriert. Sie können Ihre Worker-Threads beim Lesen der Warteschlange blockieren lassen. Alternativ können MQs mq_notify() verwenden, um einen neuen Thread zu erzeugen (oder einen bestehenden zu signalisieren), wenn ein neues Element in die Warteschlange gestellt wird. Und da es so aussieht, als würden Sie select() verwenden, kann der Bezeichner von MQ (mqd_t) als Dateideskriptor mit select.
verwendet werden