2011-05-02 32 views
11

Tôi đang cố gắng viết một chương trình mà tôi phải xem phần đầu của một số đường ống có tên sử dụng chức năng thăm dò ý kiến. Tôi có một vòng lặp for để kiểm tra mọi ống bất cứ khi nào bình chọn trả về> 0 và tôi biết rằng khi một đường ống được đóng từ thủ tục ở đầu kia, tôi sẽ nhận được POLLHUP hoặc POLLIN | POLLHUP trong lĩnh vực revents của cấu trúc pollfd.Cách sử dụng chức năng thăm dò ý kiến ​​C để xem các đường ống có tên trong Linux?

Câu hỏi của tôi là: khi một ống thực sự bị đóng và trả lại POLLHUP cho tôi, điều gì sẽ xảy ra trong vòng lặp tiếp theo? Liệu nó sẽ trả về POLLHUP một lần nữa và một lần nữa trong vòng tiếp theo và bất kỳ vòng lặp tiếp theo nào hay chức năng thăm dò ý kiến ​​sẽ bỏ qua nó sau lần POLLHUP đầu tiên?

+5

Âm thanh như thế này sẽ là khá đơn giản để tìm hiểu bằng cách thử nghiệm nó. –

+0

tôi đã thử nhưng có điều gì đó sai và pollhup trả về quá nhiều lần, nhiều hơn dự đoán vì vậy tôi chỉ tự hỏi điều gì có thể sai với mã của tôi vì vậy tôi hỏi câu hỏi đó – nikos

+2

@nikos: Bạn có thể muốn nói bình chọn bạn không còn quan tâm đến các sự kiện từ fd đó (hoặc chỉ một số sự kiện, nếu kết nối được đóng một nửa). –

Trả lời

1

dụ Minimal

Nguồn bên dưới. Cách sử dụng:

sudo mknod poll0.tmp p 
sudo mknod poll1.tmp p 
sudo chmod 666 poll*.tmp 
./poll.out 

Mở vỏ khác:

printf a > poll0.tmp 
printf b > poll1.tmp 

Output:

loop 
POLLIN i=0 n=1 buf=a 
loop 
POLLHUP i=0 
loop 
POLLIN i=1 n=1 buf=b 
POLLHUP i=1 
loop 

Vì vậy, chú ý cách poll chờ cho đến khi đọc mà không cần vòng lặp. Ví dụ

Cooler:

(while true; do date; sleep 1; done) > poll0.tmp & 
(while true; do date; sleep 2; done) > poll1.tmp & 

0 được ghi mỗi một giây, và 1 mỗi hai giây, trong đó cho thấy cách poll() là đối phó với cả hai đầu vào đồng thời, mà không trì hoãn nhau.

Nguồn:

#define _XOPEN_SOURCE 700 
#include <fcntl.h> /* creat, O_CREAT */ 
#include <poll.h> /* poll */ 
#include <stdio.h> /* printf, puts, snprintf */ 
#include <stdlib.h> /* EXIT_FAILURE, EXIT_SUCCESS */ 
#include <unistd.h> /* read */ 

int main(void) { 
    enum { N = 2 }; 
    char buf[1024], path[1024]; 
    int fd, i, n; 
    short revents; 
    struct pollfd pfds[N]; 

    for (i = 0; i < N; ++i) { 
     snprintf(path, sizeof(path), "poll%d.tmp", i); 
     /* O_NONBLOCK is required or else the open blocks 
     * until the other side of the pipe opens. */ 
     fd = open(path, O_RDONLY | O_NONBLOCK); 
     if (fd == -1) { 
      perror("open"); 
      exit(EXIT_FAILURE); 
     } 
     pfds[i].fd = fd; 
     /* Only events in this mask will be listened to. 
     * However, there are also some events that are unmaskable, 
     * notably POLLHUP when pipe closes! */ 
     pfds[i].events = POLLIN; 
    } 
    while (1) { 
     puts("loop"); 
     i = poll(pfds, N, -1); 
     if (i == -1) { 
      perror("poll"); 
      exit(EXIT_FAILURE); 
     } 
     for (i = 0; i < N; ++i) { 
      revents = pfds[i].revents; 
      if (revents & POLLIN) { 
       n = read(pfds[i].fd, buf, sizeof(buf)); 
       printf("POLLIN i=%d n=%d buf=%.*s\n", i, n, n, buf); 
      } 
      if (revents & POLLHUP) { 
       printf("POLLHUP i=%d\n", i); 

       /* This happens when the other side closed. 
       * This event is only cleared when we close the reader. */ 

       /* poll won't set POLLHUP anymore once all fds are closed. 
       * Any futher polls on this will give the POLLNVAL event instead. */ 
       close(pfds[i].fd); 

       /* negative fds are ignored. So if we negate an FD, 
       * we can both turn if off for a while, and turn it on 
       * later on by re-nagating it. */ 
       pfds[i].fd *= -1; 
      } 
     } 
    } 
} 

Compile với:

gcc -o poll.out -std=c99 poll.c 

Tested trong Ubuntu 14.04.

GitHub upstream.

Để trả lời câu hỏi ban đầu:

khi một đường ống không thực sự được đóng lại và trả về POLLHUP với tôi, điều gì sẽ xảy ra trên vòng lặp tiếp theo? Liệu nó sẽ trả về POLLHUP một lần nữa và một lần nữa trong vòng tiếp theo và bất kỳ vòng lặp tiếp theo nào hay chức năng thăm dò ý kiến ​​sẽ bỏ qua nó sau lần POLLHUP đầu tiên?

Tháo dòng:

close(pfds[i].fd); 
pfds[i].fd *= -1; 

và bạn sẽ thấy rằng nó lặp mãi mãi trên POLLHUP.

Remove chỉ:

close(pfds[i].fd); 

và bạn nhận POLLNVAL thay vào đó, vì nó cố gắng sử dụng một fd khép kín: Linux socket handling revents POLLERR POLLHUP POLLNVAL

Các vấn đề liên quan