Ich möchte einen Multithread-UDP-Server in C / Linux entwickeln. Der Dienst läuft auf einem einzigen Port x, daher besteht nur die Möglichkeit, einen einzelnen UDP-Socket an ihn zu binden. Um unter hohen Lasten zu arbeiten, habe ich n Threads (statisch definiert), sagen wir 1 Thread pro CPU. Mit dem Befehl epoll_wait kann die Arbeit an den Thread übergeben werden, sodass die Threads bei Bedarf mit "EPOLLET |" geweckt werden EPOLLONESHOT '. Ich habe ein Codebeispiel beigefügt:
%Vor%Ist das der richtige Umgang mit diesem Szenario mit epoll? Sollte die Funktion _handle_request_ so schnell wie möglich zurückkommen, weil für diese Zeit die Ereigniswarteschlange für den Socket blockiert ist?!
Danke für die Antworten!
Da Sie nur einen einzelnen UDP-Socket verwenden, ist es nicht sinnvoll, epoll zu verwenden - verwenden Sie stattdessen einen blockierenden recvfrom.
Nun können Sie je nach Protokoll, das Sie verarbeiten müssen, - wenn Sie jedes UDP-Paket einzeln verarbeiten können - recvfrom gleichzeitig von mehreren Threads (in einem Thread-Pool) aus aufrufen. Das Betriebssystem wird dafür sorgen, dass genau ein Thread das UDP-Paket erhält. Dieser Thread kann dann alles tun, was in handle_request getan werden muss.
Wenn Sie jedoch die UDP-Pakete in einer bestimmten Reihenfolge verarbeiten müssen, haben Sie wahrscheinlich nicht so viele Möglichkeiten, Ihr Programm zu paralalisieren ...
Nein, das wird nicht so funktionieren, wie Sie es wollen. Damit Worker-Threads Ereignisse verarbeiten, die über eine Epoll-Schnittstelle eingehen, benötigen Sie eine andere Architektur.
Beispielentwurf (es gibt mehrere Möglichkeiten, dies zu tun) Verwendet: SysV / POSIX-Semaphore.
Lassen Sie den Master-Thread n Unterthreads und einen Semaphor spawnen und blockieren Sie dann Ihre Sockets (oder was auch immer).
Lassen Sie jeden Unterblock den Semaphor herunterfahren.
Wenn der Hauptthread entsperrt wird, werden die Ereignisse in einer globalen Struktur gespeichert und der Semaphor einmal pro Ereignis aktualisiert.
Die Unterthreads entsperren, verarbeiten die Ereignisse, blockieren erneut, wenn der Semaphor auf 0 zurückgeht.
Sie können eine unter allen Threads freigegebene Pipe verwenden, um eine sehr ähnliche Funktionalität wie die des Semaphors zu erreichen. Dadurch können Sie select()
anstelle des Semaphors blockieren, mit dem Sie die Threads bei einem anderen Ereignis (Zeitüberschreitungen, andere Pipes usw.) aufwecken können.
Sie können dieses Steuerelement auch umkehren und den Master-Thread aktivieren, wenn seine Worker Aufgaben anfordern. Ich denke jedoch, dass der obige Ansatz für Ihren Fall besser ist.