初识select
系统提供select函数来实现多路复用输入/输出模型:
select系统调用是用来让我们的程序监视多个文件描述符的状态变化的;程序会停在select这里等待,直到被监视的文件描述符有一个或多个发生了状态改变;
Select函数原型
intselect;
参数解释:
参数n股票量化交易软件,fds是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集合及异常文件描述符的集合;参数timeout为结构timeval,用来设置select的等待时间。
参数timeout的设置:
NULL:则表示select没有timeout,select将一直被阻塞,直到某个文件描述符上发生了事件;0:仅检测描述符集合的状态,然后立即返回,并不等待外部事件的发生。特定的时间值:如果在指定的时间段里没有事件发生,select将超时返回。
股票量化交易软件,fd_set类型解析
在使用select函数时,就免不了用到fd_set结构体。那fd_set就是怎么样的?下面我们先看在man手册中关于select:那么fd_set究竟是什么?
typedef long int __fd_mask;
/* It"s easier to assume 8-bit bytes than to get CHAR_BIT. */
#define __NFDBITS (8 * (int) sizeof (__fd_mask))
#define __FDELT(d) ((d) / __NFDBITS)
#define __FDMASK(d) ((__fd_mask) 1 << ((d) % __NFDBITS))
/* fd_set for select and pselect. */
typedef struct
{
/* XPG4.2 requires this member name. Otherwise avoid the name
from the global namespace. */
#ifdef __USE_XOPEN
__fd_mask fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->fds_bits)
#else
__fd_mask __fds_bits[__FD_SETSIZE / __NFDBITS];
# define __FDS_BITS(set) ((set)->__fds_bits)
#endif
} fd_set;
/* Maximum number of file descriptors in `fd_set". */
#define FD_SETSIZE __FD_SETSIZE //__FD_SETSIZE等于1024
/* Access macros for `fd_set". */
#define FD_SET(fd, fdsetp) __FD_SET (fd, fdsetp)
#define FD_CLR(fd, fdsetp) __FD_CLR (fd, fdsetp)
#define FD_ISSET(fd, fdsetp) __FD_ISSET (fd, fdsetp)
#define FD_ZERO(fdsetp) __FD_ZERO (fdsetp)
根据分析,我么可以把这个结构理解为一个整数数组,更严格的说,是一个“位”。使用位中对应的位来表示要监视的文件描述符。????????????并且还提供了一组操作fd_set的接口函数,来方便的操作该位!
voidFD_CLR;//用来清除描述词组set中相关fd的位intFD_ISSET;//用来测试描述词组set中相关fd的位是否为真voidFD_SET;//用来设置描述词组set中相关fd的位voidFD_ZERO;//用来清除描述词组set的全部位
函数的返回值
执行成功则返回文件描述词状态已改变的个数。如果返回0代表在描述词状态改变前已超过timeout时间,没有返回。当有错误发生时则返回-错误原因存于errno,此时参数readfds,writefds,exceptfds和timeout的值变成不可预测。
其中,错误值可能为:
EBADF文件描述词为无效的或该文件已关闭。EINTR此调用被信号所中断。EINVAL参数n为负值。ENOMEM核心内存不足。
理解Select的执行过程
理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个文件描述符fd。则1字节长的fd_set最大可以对应8个fd。
执行fd_setset;FD_ZERO;则set用位表示是0000,0000。若fd=5,执行FD_SET;后set变为0001,0000。若再加入fd=fd=1,则set变为0001,001执行select阻塞等待。若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,001注意:没有事件发生的fd=5被清空。
Select的特点
可监控的文件描述符个数取决与sizeof的值。我这边服务器上sizeof=51每bit表示一个文件描述符,则我服务器上支持的最大文件描述符是512*8=409将fd加入select监控集的还要再使用一个数据结构array保存放到select监控集中的fd。
这里我们思考为什么需要额外的数据结构array保存放到select监控集中的fd?
一是用于再select返回后,array作为源数据和fd_set进行FD_ISSET判断。二是select返回后会把以前加入的但并无事件发生的fd清空,则每次开始select前都要重新从array取得fd逐一加入,扫描array的同时取得fd最大值maxfd,用于select的第一个参数。
也正是因为以上两点,Select也有不得不说的缺点!!!
每次调用select,都需要手动设置fd集合,从接口使用角度来说也非常不便。每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大。同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大。select支持的文件描述符数量太小。
Select的简单示例
只检测标准输入:
#include <stdio.h>
#include <unistd.h>
#include <sys/select.h>
int main() {
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(0, &read_fds);
for (;;) {
printf("> ");
fflush(stdout);
int ret = select(1, &read_fds, NULL, NULL, NULL);
if (ret < 0) {
perror("select");
continue;
}
if (FD_ISSET(0, &read_fds)) {
char buf[1024] = { 0 };
read(0, buf, sizeof(buf) - 1);
printf("input: %s", buf);
}
else {
printf("error! invaild fd
");
continue;
}
FD_ZERO(&read_fds);
FD_SET(0, &read_fds);
}
return 0;
}
select示例代码
文章为作者独立观点,不代表 股票程序化软件自动交易接口观点