Linux select和poll系统调用
2015-08-11 17:50
603 查看
很多时候,我们调用read函数从文件描述符中读取数据时,如果此时恰好没有数据可读,read系统调用势必会阻塞住。同样,当调用write函数时,而没有空间供我们写入,write系统调用也会被阻塞住,直到有空间被写入时。那么在这种情况下我们为了不阻塞我们的程序,就需要检查文件描述符是否可读或可写。
1. select系统调用
首先我们来看一段代码:
上面这段代码是从标准输入端读取字符并显示出来,如果我们不输入任何字符,那么read函数是会被阻塞的,直到我们输入了任意字符并按了回车键。那么如何避免被阻塞呢,来看select系统调用,原型如下:
参数nfds必须设定为比3个文件描述符集合中的所包含的最大文件描述符还要大1,什么意思呢,假如我们只关注read,而read集合中包含两个文件描述符,它们的值分别为2、3,那么这里nfds就必须设置为大于等于3+1。
参数timeout为超时时间。
使用select系统调用的示例如下:
2. poll系统调用
poll系统调用同select系统调用类似,原型如下:
上面的代码使用poll系统调用修改如下:
参考教程:The Linux Programming Interface - A Linux and UNIX System Programming Handbook.pdf
1. select系统调用
首先我们来看一段代码:
#include <stdio.h> #include <unistd.h> int main(void) { int bytes_read; char buffer[128]; bytes_read = read(STDIN_FILENO, buffer, sizeof(buffer)); if (buffer[bytes_read - 1] == '\n') buffer[bytes_read - 1] = '\0'; printf("%s\n", buffer); return 0; }
上面这段代码是从标准输入端读取字符并显示出来,如果我们不输入任何字符,那么read函数是会被阻塞的,直到我们输入了任意字符并按了回车键。那么如何避免被阻塞呢,来看select系统调用,原型如下:
#include <sys/select.h> int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);参数readfds、writefds、exceptfds都是指向文件描述符的指针,数据类型为fd_set。而readfds是用来检测输入的,writefds是用来检测输出的,exceptfds使用检测是否异常的。有关fd_set通常有四个宏供我们操作:FD_ZERO、FD_SET、FD_CLR、FD_ISSET。
void FD_CLR(int fd, fd_set *set); int FD_ISSET(int fd, fd_set *set); void FD_SET(int fd, fd_set *set); void FD_ZERO(fd_set *set);FD_ZERO是将fd_set所指向的集合清空,FD_SET是将文件描述符fd添加到fd_set所指向的集合中,FD_CLR是将文件描述符fd从fd_set所指向的集合中移除,而如果文件描述符fd是fd_set所指向的集合中的成员,则FD_ISSET返回true,否则返回false。文件描述符集合有一个最大容量限制,由常量FD_SETSIZE来决定,在Linux上,该常量值为1024。
参数nfds必须设定为比3个文件描述符集合中的所包含的最大文件描述符还要大1,什么意思呢,假如我们只关注read,而read集合中包含两个文件描述符,它们的值分别为2、3,那么这里nfds就必须设置为大于等于3+1。
参数timeout为超时时间。
使用select系统调用的示例如下:
#include <stdio.h> #include <unistd.h> #include <sys/select.h> int main(void) { int bytes_read, ready; char buffer[128]; fd_set readfds; struct timeval timeout; FD_ZERO(&readfds); FD_SET(STDIN_FILENO, &readfds); timeout.tv_sec = 10; timeout.tv_usec = 0; ready = select(STDIN_FILENO+1, &readfds, NULL, NULL, &timeout); if (ready) { bytes_read = read(STDIN_FILENO, buffer, sizeof(buffer)); if (buffer[bytes_read - 1] == '\n') buffer[bytes_read - 1] = '\0'; printf("%s\n", buffer); } else { printf("No data to read\n"); } return 0; }如果没有数据可读,select系统调用也是会被阻塞的,直到超时为止,这里设定是的10秒。如果没有指定timeout参数,则select系统调用会永远阻塞下去。
2. poll系统调用
poll系统调用同select系统调用类似,原型如下:
#include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout);struct pollfd定义如下:
struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ short revents; /* returned events */ };参数nfds为fds元素个数。timeout为超时时间,单位为毫秒,如果timeout等于-1,poll系统调用会一直阻塞,如果timeout等于0,则poll系统调用之检测一次并立即退出,如果timeout大于0,则poll系统调用会最多阻塞timeout毫秒,直到数据可读或可写。
上面的代码使用poll系统调用修改如下:
#include <stdio.h> #include <unistd.h> #include <poll.h> int main(void) { int bytes_read, ready; char buffer[128]; struct pollfd readfds; readfds.fd = STDIN_FILENO; readfds.events = POLLIN; ready = poll(&readfds, 1, 10000); if (ready) { bytes_read = read(STDIN_FILENO, buffer, sizeof(buffer)); if (buffer[bytes_read - 1] == '\n') buffer[bytes_read - 1] = '\0'; printf("%s\n", buffer); } else { printf("No data to read\n"); } return 0; }
参考教程:The Linux Programming Interface - A Linux and UNIX System Programming Handbook.pdf
相关文章推荐
- linux中静态库和动态库的区别
- 精通linux设备驱动开发 笔记
- linux设备驱动归纳总结(三):1.字符型设备之设备申请
- Linux下的AWK入门教程
- Linux下,PHP的SESSION不起作用的问题
- Linux进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)
- Linux开机自启动程序详解
- windows和linux双系统修改启动项顺序
- Linux系统下UDP发送和接收广播消息小例子
- Centos 7 固定ip配置
- [Linux]查看系统信息方法汇总
- 欢迎使用CSDN-markdown编辑器
- 理解 Linux 配置文件【转】
- kafka broker集群
- 查看 Linux 是32位还是64位的
- 使用linux交叉编译mono
- Linux rpm 命令参数使用详解[介绍和应用]
- linux下的锁机制
- Linux系统中的数据流重定向和管道
- 5.【SELinux学习笔记】类型增强