嵌入式 select用于实现I/O多路复用示例

本文深入探讨了阻塞与非阻塞操作的区别,阐述了如何通过设置socket为非阻塞方式实现轮询,以及select()函数如何用于实现I/O多路复用,有效避免函数因等待资源而阻塞,提高系统性能。
阻塞和非阻塞
  阻塞函数在完成其指定的任务以前不允许程序调用另一个函数。例如,程序执行一个读数据的函数调用时,在此函数完成读操作以前将不会执行下一程序语句。当服务器运行到accept语句时,而没有客户连接服务请求到来,服务器就会停止在accept语句上等待连接服务请求的到来。这种情况称为阻塞(blocking)。而非阻塞操作则可以立即完成。比如,如果你希望服务器仅仅注意检查是否有客户在等待连接,有就接受连接,否则就继续做其他事情,则可以通过将Socket设置为非阻塞方式来实现。非阻塞socket在没有客户在等待时就使accept调用立即返回。
#include
  #include
  ……
sockfd = socket(AF_INET,SOCK_STREAM,0);
fcntl(sockfd,F_SETFL,O_NONBLOCK);
……
通过设置socket为非阻塞方式,可以实现"轮询"若干Socket。当企图从一个没有数据等待处理的非阻塞Socket读入数据时,函数将立即返回,返回值为-1,并置errno值为EWOULDBLOCK。但是这种"轮询"会使CPU处于忙等待方式,从而降低性能,浪费系统资源。而调用select()会有效地解决这个问题,它允许你把进程本身挂起来,而同时使系统内核监听所要求的一组文件描述符的任何活动,只要确认在任何被监控的文件描述符上出现活动,select()调用将返回指示该文件描述符已准备好的信息,从而实现了为进程选出随机的变化,而不必由进程本身对输入进行测试而浪费CPU开销。
select用于实现I/O多路复用,防止函数没有得到资源而阻塞,长期占用CPU.
#include
#include
#include
int select(int n,fd_set * readfds,fd_set * writefds,fd_set *exceptfds,struct timeval * timeout);
select()用来等待文件描述词状态的改变。参数n代表最大的文件描述词加1,参数readfds、writefds和exceptfds 称为
描述词组,是用来回传该描述词的读,写或例外的状况。底下的宏提供了处理这三种描述词组的方式:
FD_CLR(inr fd,fd_set* set);用来清除描述词组set中相关fd 的位
FD_ISSET(int fd,fd_set *set);用来测试描述词组set中相关fd 的位是否为真
FD_SET(int fd,fd_set*set);用来设置描述词组set中相关fd的位
FD_ZERO(fd_set *set); 用来清除描述词组set的全部位

参数 timeout为结构timeval,用来设置select()的等待时间,其结构定义如下
struct timeval
{
time_t tv_sec;
time_t tv_usec;
};

返回值 如果参数timeout设为NULL则表示select()没有timeout。
执行成功则返回文件描述词状态已改变的个数,如果返回0代表在描述词状态改变前已超过timeout时间,当有错误发生时
则返回-1,错误原因存于errno,此时参数readfds,writefds,exceptfds和timeout的值变成不可预测。
EBADF 文件描述词为无效的或该文件已关闭
EINTR 此调用被信号所中断
EINVAL 参数n 为负值。
ENOMEM 核心内存不足

范例 常见的程序片段:fs_set readset;
FD_ZERO(&readset);
FD_SET(fd,&readset);
select(fd+1,&readset,NULL,NULL,NULL);
if(FD_ISSET(fd,readset){……}
例:
#include
#include
#include
#include
#include
int main ()
{
int keyboard;
int ret,i;
char c;
fd_set readfd;
struct timeval timeout;
keyboard = open("/dev/tty",O_RDONLY | O_NONBLOCK);
assert(keyboard>0);
while(1)
{
timeout.tv_sec=5;
timeout.tv_usec=0;
FD_ZERO(&readfd);
FD_SET(keyboard,&readfd);
ret=select(keyboard+1,&readfd,NULL,NULL,&timeout);
//select error when ret = -1
if (ret == -1)
perror("select error");
//data coming when ret>0
else if (ret)
{
if(FD_ISSET(keyboard,&readfd))
{
i=read(keyboard,&c,1);
if('/n'==c)
continue;
printf("hehethe input is %c/n",c);
if ('q'==c)
break;
}
}
//time out when ret = 0
else if (ret == 0)
printf("time out/n");
}
}
本项目采用Python编程语言与Jupyter环境,构建了一套用于光伏发电功率预测的完整解决方案,包含源代码、数据集及详细算法说明,适用于学术研究、课程实践及工程开发等场景。全部代码均经过充分验证,具备良好的可扩展性,具体实施细节可参阅相关文档。 项目核心目标为:基于历史气象预报数据及其对应的光伏发电功率记录,训练预测模型,进而结合未来特定时刻的气象预报信息,估算该时刻的发电功率。 算法设计要点如下: 1. 评估机制中剔除了发电功率低于设定阈值的数据样本。根据太阳辐照度与功率阈值之间的关联性,可将数据划分为两类:一类包含辐照度为-1的记录,另一类则排除此类数据。在预测过程中,所有低于阈值的输出将被自动修正至阈值水平,以提升预测精度。 2. 通过分析太阳辐射变化模式,推断日出时刻,并将十个电站的地理位置归纳为四个区域:海西、哈密、西宁与乌鲁木齐。借助R语言的OCE工具包,输入时间与地理位置信息,可获取太阳高度角、赤纬角及预估辐照强度等关键特征,并将其整合至数据集中。 3. 光伏发电功率表现出明显的日周期与季节波动特性,适宜作为时间序列进行分析。采用Facebook开发的fbprophet时间序列分析工具,对训练数据中的时间与功率关系进行建模拟合,从而捕捉其内在规律与趋势变化。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值