select
定时器 + 轮询(单线程)上周写了 怎么样获取系统时间
这周写一个
定时 + 轮询
的.在单线程上实现这个感觉没有什么用,有点多此一举… 但是这个时间的逻辑处理还是可以的…
select
函数#include
#include
#include
int main(int argc, char const *argv[]){
int ret = 0;
fd_set rfds = {0};
struct timeval tv = {0};
FD_ZERO(&rfds);
FD_SET(0, &rfds);
tv.tv_sec = 1;
tv.tv_usec = 0;
ret = select(1, &rfds, NULL, NULL, &tv);
if(ret == -1){
perror("select error");
} else if(ret){
printf("receive data from to STDIN\n\n");
}else {
printf("timeout\n\n");
}
return 0;
}
运行结果:
baoshaohua:定时器 bao$ ./select_learning
timeout
baoshaohua:定时器 bao$ ./select_learning
d
receive data from to STDIN
baoshaohua:定时器 bao$ d
bash: d: command not found
在 select函数监听标准输入0
(键盘), 5s内如果有输入就返回值大于0;
如果没有输入就返回0,表示超时了.
前几天发现, 在使用
man select
的时候, 在mac上的结果没有在Linux系统的结果详细…后面会列举几点.
试了一下其他函数, 也是这样.
所以page还是得在linux上查.
#include
#include
#include
#include
#include
typedef void (* timer_func)(char *param);
//保存定时的时间
int running = 0;
struct timeval duration = {
0};
struct timeval deadtime = {
0};
timer_func test_func = NULL;
char *test_func_param = NULL;
int i = 0;
//每次轮询都会计算轮询的时间
void recalculate_time(struct timeval *tv)
{
struct timeval now2;
struct timeval deadtime2;
gettimeofday(&now2, NULL);
memcpy(&deadtime2, &now2, sizeof(struct timeval));
deadtime2.tv_sec += 1;
if(timercmp(&deadtime2, &deadtime, >)){
// printf("333deadtime.tv_sec[%ld], deadtime.tv_usec[%d] \n", deadtime.tv_sec, deadtime.tv_usec);
// printf("333deadtime2.tv_sec[%ld], deadtime2.tv_usec[%d] \n", deadtime2.tv_sec, deadtime2.tv_usec);
// printf("333now2.tv_sec[%ld], now2.tv_usec[%d] \n\n", now2.tv_sec, now2.tv_usec);
memcpy(&deadtime2, &deadtime, sizeof(struct timeval));
test_func(test_func_param);
// printf("333deadtime.tv_sec[%ld], deadtime.tv_usec[%d] \n", deadtime.tv_sec, deadtime.tv_usec);
// printf("333deadtime2.tv_sec[%ld], deadtime2.tv_usec[%d] \n", deadtime2.tv_sec, deadtime2.tv_usec);
// printf("333now2.tv_sec[%ld], now2.tv_usec[%d] \n\n", now2.tv_sec, now2.tv_usec);
}
if(timercmp(&deadtime2, &now2, >)){
printf("[0000]\n\n");
timersub(&deadtime2, &now2, tv);
} else {
printf("[1111]\n\n");
timerclear(tv);
running = 0;
}
// printf("[%d]\n\n", ++i);
// printf("222tv.tv_sec[%ld], tv.tv_usec[%d] \n\n", tv->tv_sec, tv->tv_usec);
}
//处理定时模块
int dispatch_timer_module()
{
int ret = 0;
fd_set rfds = {
0};
// fd_set wfds = {0};
struct timeval tv = {
0};
//如果在这,轮询的第一秒终端输入才可以收到数据..其他时间不可以
// FD_ZERO(&rfds);
// FD_ZERO(&wfds);
// FD_SET(0, &rfds);
// FD_SET(1, &wfds);
running = 1;
while(running){
FD_ZERO(&rfds);
FD_SET(0, &rfds);
recalculate_time(&tv);
// 在退出时,将修改每个文件描述符集,以指示哪个文件描述符实际更改了状态。(因此,如果在循环中使用select(),则必须在每次调用之前重新初始化集合。)
ret = select(1, &rfds, NULL, NULL, &tv);
printf("ret [%d]\n", ret); //超时返回0
if(ret < 0){
//出错
perror("select error:");
continue;
}
if(ret > 0){
printf("[data]\n");
goto end;
}
}
end:
return ret;
}
//注册超时调用的函数, 超时时间, 死亡时间等
int add_timer_module(int sec, timer_func func, void *param)
{
int ret = 0;
struct timeval now1 = {
0};
struct timeval deadtime1 = {
0};
gettimeofday(&now1, NULL);
printf("111now1.tv_sec[%ld], now1.tv_usec[%d] \n\n", now1.tv_sec, now1.tv_usec);
duration.tv_sec = sec / 1000;
duration.tv_usec = (sec % 1000)*1000;
printf("111duration.tv_sec[%ld], duration.tv_usec[%d] \n\n", duration.tv_sec, duration.tv_usec);
timeradd(&now1, &duration, &deadtime);
test_func = func;
test_func_param = param;
printf("111deadtime.tv_sec[%ld], deadtime.tv_usec[%d] \n\n", deadtime.tv_sec, deadtime.tv_usec);
dispatch_timer_module();
return ret;
}
void timeout_handle_func(char *str)
{
printf("[timeout] %s\n", str);
}
int main(int argc,char const *argv[]){
char buf[10] = "bao";
add_timer_module(5*1000, timeout_handle_func, buf);
printf("\n\n");
struct timeval tt = {
0};
gettimeofday(&tt, NULL);
printf("tt.tv_sec[%ld], tt.tv_usec[%d] \n\n", tt.tv_sec, tt.tv_usec);
timerclear(&tt);
printf("tt.tv_sec[%ld], tt.tv_usec[%d] \n\n", tt.tv_sec, tt.tv_usec);
return 0;
}
运行结果(超时的结果):
111now1.tv_sec[1587736629], now1.tv_usec[602669]
111duration.tv_sec[5], duration.tv_usec[0]
111deadtime.tv_sec[1587736634], deadtime.tv_usec[602669]
[0000]
ret [0]
[0000]
ret [0]
[0000]
ret [0]
[0000]
ret [0]
[timeout] bao
[0000]
ret [0]
[timeout] bao
[1111]
ret [0]
tt.tv_sec[1587736634], tt.tv_usec[607379]
tt.tv_sec[0], tt.tv_usec[0]
1、
add_timer_modul
这个函数.
第一个参数试设置的超时时间.
第二个参数试超时调用的函数.
第三个参数试第二个参数的参数.
2、实现了在5s内如果键盘没有输入就返回超时.并调用超时函数.并且按照1秒轮询…
如果有输入的话,就退出超时…
3、单线程,感觉没什么意义…可以做成多线程, 去轮询其他的模块.
问题1: 只有在一运行的时候才能输入, 其他时候不退出…
select
函数每次执行完, 描述符集就改变了, 刚开始我并没有每次循环将0放到描述符集中
问题2: 会发现超时的时候会出现两次timeout
其实第一次并没有真正超时,
比如, 死亡时间是
10.100
, 现在时间是9.101
,当9.101
+ 1的时候以为是超时了,其实没有…
欢迎关注公众号: