2009-10-20 31 views
8

Tôi cần chương trình của mình được viết bằng chữ C thuần túy để dừng thực thi khi stdin bị đóng.Làm thế nào để kiểm tra xem stdin vẫn mở mà không bị chặn?

Có công việc không xác định được thực hiện trong chu trình chính của chương trình và không có cách nào tôi có thể sử dụng kiểm tra chặn (như getc()) ở đó (không có dữ liệu nào đến trên stdin - nó vẫn mở trong thời gian không xác định).

Tôi dự định sử dụng chức năng được mô tả trong việc thực hiện mạng daemon được lưu trữ trong inetd, xinetd hoặc các tương tự của chúng - nó sẽ phát ra dữ liệu trên thiết bị xuất chuẩn trong khi kết nối vẫn mở và hoàn thành công việc khi đóng. Bây giờ chương trình của tôi bị giết bởi dịch vụ lưu trữ vì nó sẽ không dừng lại sau khi chấm dứt kết nối.

Tôi tự hỏi nếu fctntl() với cờ O_NONBLOCK áp dụng cho bộ mô tả stdin sẽ cho phép tôi sử dụng chức năng read() ở chế độ không chặn không? Tôi có nên sử dụng select() bằng cách nào đó không?

P.S. Dữ liệu không được cho là nhưng có thể đến stdin. Một cách đọc không chặn sẽ là câu trả lời cho câu hỏi.

Trả lời

6

chọn() thực hiện chính xác những gì bạn muốn: báo hiệu rằng thao tác (đọc, trong trường hợp này) trên bộ mô tả tệp (tệp, ổ cắm, bất kỳ thứ gì) sẽ không chặn.

#include <stdio.h> 
#include <sys/select.h> 

int is_ready(int fd) { 
    fd_set fdset; 
    struct timeval timeout; 
    int ret; 
    FD_ZERO(&fdset); 
    FD_SET(fd, &fdset); 
    timeout.tv_sec = 0; 
    timeout.tv_usec = 1; 
    //int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, 
    struct timeval *timeout); 
    return select(fd+1, &fdset, NULL, NULL, &timeout) == 1 ? 1 : 0; 
} 

Bây giờ bạn có thể kiểm tra một mô tả tập tin trước khi sử dụng, ví dụ để làm trống bộ mô tả file:

void empty_fd(int fd) { 
    char buffer[1024]; 
    while (is_ready(fd)) { 
     read(fd, buffer, sizeof(buffer)); 
    } 
} 

Trong trường hợp của bạn, sử dụng fileno (stdin) để có được những mô tả tập tin của stdin:

if (is_ready(fileno(stdin))) { 
    /* read stuff from stdin will not block */ 
} 
+0

'poll' cũng chính xác là những gì OP muốn, và giao diện của nó dễ dàng hơn một chút so với' select' khi giao dịch với một bộ mô tả tập tin nhỏ, cố định. – ephemient

0

Có gì sai với feof(stdin)?

+0

Điều đó sẽ không hoạt động nếu bạn không đọc tất cả dữ liệu. Làm cách nào để đọc tất cả dữ liệu (ví dụ: thùng rác) mà không chặn hoạt động? – Basilevs

+0

EOF có thể được chèn vào một stdin mở (ví dụ: thông qua Ctrl-D trên Linux). Nó không có nghĩa là stdin bị đóng. –

1

Tôi không chắc chắn liệu bạn có thể đặt O_NONBLOCK trên stdin hay không, nhưng select() hoặc poll() chắc chắn sẽ hoàn thành công việc.

+0

Có, bạn có thể đặt O_NONBLOCK trên stdin. Tuy nhiên, nếu stdin của bạn được đường ống từ một chương trình khác, chương trình đó có thể không xử lý mô tả tệp đi của nó trở thành không chặn rất tốt. – ephemient

0

Có, bạn có thể sử dụng select (với thời gian chờ bằng 0). Tuy nhiên, bạn không cần đặt trình mô tả tệp không chặn - nếu select cho bạn biết rằng bộ mô tả tệp có thể đọc được, thì read sẽ không chặn được.

Vì vậy, bộ mô tả tập tin phiếu thăm dò ý kiến ​​0 thỉnh thoảng với select và nếu nó có thể đọc được, read. Nếu read trả về 0, điều đó có nghĩa là nó đã bị đóng.

2

tôi tự hỏi nếu fctntl() với O_NONBLOCK cờ áp dụng cho mô tả stdin wo uld cho phép tôi sử dụng hàm read() ở chế độ không chặn?

Chạy stdin với O_NONBLOCK có lợi thế hơn lựa chọn. Chọn nói rằng có một số dữ liệu, nhưng không bao nhiêu. Có những lúc bạn muốn nhận tất cả dữ liệu có sẵn, nhưng không chặn, bất kể số lượng hàng trong hàng đợi. Chạy lựa chọn cho mỗi nhân vật có vẻ như rất nhiều công việc bận rộn ... O_NONBLOCK không làm việc cho tôi. Nó là một lá cờ nội bộ, không được phơi bày trong hầu hết các trình điều khiển tty.

Xem ioctl (..., FIONBIO). Dường như để hoàn thành công việc.

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