Nicht blockierender Aufruf zum Lesen des Deskriptors

Lesezeit: 4 Minuten

Benutzeravatar von SmallChess
Kleines Schach

Ich habe einen fd-Deskriptor, aus dem ich durch Aufrufen lesen kann read(fd, buffer,...). Jetzt möchte ich prüfen, ob es etwas zu lesen gibt, bevor ich den Anruf tatsächlich tätige, da der Anruf blockiert ist. Wie mache ich das?

  • Das Verhalten von read in Bezug auf das Blockieren variiert je nach Deskriptortyp. Zu welcher Art von Gerät passt fd verweisen?

    – kqnr

    11. April 2011 um 1:59 Uhr

  • Standardeingänge blockieren gerade jetzt

    – Kleines Schach

    11. April 2011 um 2:00 Uhr

  • @KenRockot also, wenn ich eine normale Datei habe, ist es anders als zum Beispiel fd, das ein socketDescriptor ist?

    – Bionix1441

    19. April 2016 um 17:18 Uhr

Benutzeravatar von Judge Maygarden
Richter Maygarden

int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);

Das obige Code-Snippet konfiguriert einen solchen Deskriptor für den nicht blockierenden Zugriff. Wenn beim Aufrufen von read keine Daten verfügbar sind, schlägt der Systemaufruf mit einem Rückgabewert von -1 fehl und errno wird auf EAGAIN gesetzt. Siehe die Funktion man-Seiten für weitere Informationen.

Alternativ können Sie verwenden auswählen mit einem konfigurierbaren Timeout zum Überprüfen und/oder Warten eines bestimmten Zeitintervalls auf weitere Daten. Diese Methode ist wahrscheinlich das, was Sie wollen und kann viel effizienter sein.

  • Und dann prüfen Sie, ob -1 von zurückgegeben wird read und das errno ist EAGAIN.

    – mu ist zu kurz

    11. April 2011 um 2:06 Uhr

  • gutes Dokument über Datei mit nicht blockierender Support-Einstellung errno at offene Gruppe

    – qrtLs

    4. Juli 2016 um 16:11 Uhr


  • Dies ist NICHT die richtige Antwort. O_NONBLOCK gegen ein reguläres fs hat keine Wirkung (read() blockiert weiter) und select() meldet das fd immer fälschlicherweise als “bereit”. Zuverlässiges, nicht blockierendes IO für reguläre Dateien unter Linux wird grundsätzlich (und leider) nicht unterstützt.

    – Giampaolo Rodola

    19. Dezember 2016 um 12:14 Uhr

  • Etwas gut Quellen auf reguläre Dateien und nicht blockierende E/A. jedoch, wenn fd ist stdin, dann scheint es harmlos zu sein O_NONBLOCK Beschleunigen Sie die Dinge beim Lesen von einem Terminal / einer Pipe und tun Sie nichts, wenn Sie von einer Datei lesen.

    – Paul A. Jungwirth

    6. Mai 2017 um 7:07 Uhr

R.. GitHub STOP HELPING ICEs Benutzeravatar
R.. GitHub HÖREN SIE AUF, ICE ZU HELFEN

Verwenden select oder poll um abzufragen, ob der Dateideskriptor Daten zum Lesen bereithält:

fd_set fds;
FD_ZERO(&fds);
FD_SET(&fds, fd);
if (select(fd+1, &fds, 0, 0)==1) /* there is data available */

  • Ist nicht FD_SET(fd, &fds); stattdessen ?

    – malat

    27. Januar 2015 um 12:46 Uhr

  • Wahrscheinlich, aber select ist sowieso eine schreckliche Idee, weil FD_SET ruft UB auf, wenn fd>=FD_SETSIZE. Benutz einfach poll.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    27. Januar 2015 um 17:16 Uhr

  • poll() ist jetzt in POSIX standardisiert, sodass es immer anstelle von verwendet werden kann select(). pubs.opengroup.org/onlinepubs/009695399/functions/poll.html

    – Lassi

    3. Mai 2018 um 8:09 Uhr

  • Ja, poll sollte stattdessen verwendet werden.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    3. Mai 2018 um 16:17 Uhr

  • IIRC-Abfrage auf macOS UND serieller Schnittstelle funktioniert nicht. Ich konnte die Referenz jetzt nicht finden, aber ich habe eine deutliche Erinnerung, dass dies der Fall ist oder war. Da dies eine alte Frage war, die nicht Linux-spezifisch war, denke ich, dass die Empfehlung, poll() zu verwenden, schlecht sein könnte.

    – nyholku

    17. März 2020 um 6:16 Uhr

Je nachdem, was Sie tun, können Sie das Problem möglicherweise umkrempeln und verwenden select um Ihnen mitzuteilen, wenn Ihr Dateideskriptor etwas zu lesen hat.

Benutzeravatar von Ankur Soni
Ankur Soni

Abfrage für Timeout verwenden:

struct pollfd p;
int n;
while ((n = poll(&p, 1, iTo)) < 0) 
{
    if (errno == EAGAIN || errno == EINTR)
       continue;
}

if (!n) {
    errno = ETIMEDOUT;
}

while ((len = read(Fd, anyBuff, sizeof(anyenter code hereBuff))) < 0) {
    if (errno == EAGAIN || errno == EINTR)
        continue;
}

Ich denke, Sie sollten verwenden select oder poll Funktionen, um zu prüfen, ob es etwas aus dem Deskriptor zu lesen gibt.

  • Können Sie weitere Details hinzufügen? Ein Beispiel wäre schön.

    – Nathan F.

    8. Oktober 2019 um 22:56 Uhr

Benutzeravatar von Novin Shahroudi
Novin Shahroudi

Überprüfen Sie die API oder das System/Tool, das Sie für Ihren spezifischen Programmierzweck verwenden. (Deskriptoren/Dateideskriptoren haben viele Anwendungen in der Linux-Programmierung, wie z. B. Socket-Programmierung, Dateimanipulation, Shared_Memory usw.)

Zum Beispiel habe ich einmal inotify verwendet (zur Überwachung von Dateisystemereignissen). Diese API gibt Ihnen die Möglichkeit, vom ersten Punkt an eine nicht blockierende Datei zu erstellen, und es besteht keine Notwendigkeit, fcntl oder ähnliche APIs zu verwenden, um den erstellten Dateideskriptor zu ändern.

Wahrscheinlich haben andere Tools oder APIs, die Sie verwenden werden, eine solche Funktionalität, und Sie können eine solche Option bei ihrer Initiierung oder solchen Schritten festlegen (überprüfen Sie dies zuerst).

Aber im Allgemeinen ist ja die Verwendung von fcntl die Antwort, und es könnte interessant sein zu wissen, dass inotify selbst auch fcntl selbst verwendet. (siehe Handbuchseiten von Linux)

select() kann Ihnen die gleiche Funktionalität bieten wie es auf Dateideskriptoren zum Überwachen von Ereignissen mit einer bestimmten begrenzten Zeit arbeitet, aber denken Sie daran, dass die Hauptverwendung von select die Überwachung ist mehrere Dateideskriptoren.

  • Können Sie weitere Details hinzufügen? Ein Beispiel wäre schön.

    – Nathan F.

    8. Oktober 2019 um 22:56 Uhr

1408490cookie-checkNicht blockierender Aufruf zum Lesen des Deskriptors

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy