Chinaunix

标题: setitimer() && select() [打印本页]

作者: robin10    时间: 2011-01-11 19:48
标题: setitimer() && select()
有这样一个问题:

程序中,需要一个定时器,定期去检查一些东西。。
用 signal(SIGALAM,my_fun);

...
setitimer(ITIMER_REAL,&a,&b);

假设TIMEOUT是1S,可以正常工作。。


问题在于,程序中有另外一个地方,用到了select();比如说TIMEOUT是2S;

当signal()使用信号量 SIGANLAM的时候,select();不到2S就TIMEOUT了;
(相信是因为,select()也是用signal(SIGALAM,select)来计算时间的)

这样就导致了select()不可以正常工作。
而setitimer()的另外2个信号量并不适合我使用。

查了一下,alarm();其实也是使用了同样的信号量来计时的。
QA:linux MS就只提供这2个定时器(?)

QB:这中情况下,还有什么方法可以做一个计数器,而又不影响我的select()的使用呢?
QC:另外开一条线程,让它sleep()一会然后去调用my_fun() ?      MS这个可行。
QD:有什么更好的解决方法呢?

谢谢。。。
怀念g_timeout_add(); 呵呵。
作者: robin10    时间: 2011-01-11 19:55
.....如果我2个地方都是有 setitimer() or select(),相信是会出现同样的问题。
同时将2部分功能放在一个函数中,然后根据条件来判断,又不是我想要的;
定时器A,是一直需要使用的,包含select()是在必要的时候才使用。

g_timeout_add()这种定时器,MS是在主线程中注册一个callback(),然后让主线程去执行。
具体的实现,是否也是使用signal()之类的,不太清楚,希望知道的XD可以说说。
谢谢。
作者: wb112200    时间: 2011-01-11 20:06
我一般都是独立开一个线程  原公司的游戏框架代码中的TIMEER 也是这么实现的..
作者: robin10    时间: 2011-01-11 20:06
刚才man 了一下sigaction()
MS比较复杂,没用过,要再看看。。

网好像一般都是用信号量,select()或者sleep()来实现的...

我遗漏什么了吗?
作者: robin10    时间: 2011-01-11 20:13
回复 3# wb112200


    恩,这个是一个选择,不过我希望线程越少越好,所以。。。有没有什么办法可以类似select(),alarm() 之类的实现呢?

系统要是提供类似 g_timeout_add()这样的东西就好了。。哈哈,可能是以前用惯了,有点依赖性。。。

谢谢~
作者: robin10    时间: 2011-01-11 20:16
回复 3# wb112200

PS.我喜欢你的头像~~哈哈,前面看了的贴子有你的回帖,就想说了~
作者: wb112200    时间: 2011-01-11 20:18
回复 5# robin10


    我还真没想过其他的办法呢
    如果对时间的精度要求不高 大可不必考虑那些影响
作者: wb112200    时间: 2011-01-11 20:19
回复  wb112200

PS.我喜欢你的头像~~哈哈,前面看了的贴子有你的回帖,就想说了~
robin10 发表于 2011-01-11 20:16



    {:3_196:}  我也很喜欢 就贴上了 呵呵
作者: robin10    时间: 2011-01-11 20:29
回复 7# wb112200


    恩,时间精确度倒是要求不严格。
主要是我有点害怕线程。。。
呵呵,以前有个东西,有10来条线程的。。。(当然,如果对PC或者服务器,相当正常吧。。
不过我是用在arm机的。。)

然后有一个BUG,导致某1,2条线程Z掉了。。
kill 还kill不了。。。
精灵进程去重启,也不一定可以成功(估计是某些资源被占用了)。。
搞得头大。。

所以。。我的原则是,能简单尽量简单。。
作者: wb112200    时间: 2011-01-11 20:49
回复 9# robin10


    {:3_196:}  害怕...
作者: robin10    时间: 2011-01-11 20:55
回复 10# wb112200


    谢谢wb112200XD~
如果最后没有更好的办法,就使用线程吧。。。。
作者: iccc11    时间: 2011-01-11 21:10
成熟的网络库一般都集成定时器回调和socket通知,大致上都是底层挂一个rbtree或者堆(里边的节点是按照时间排序的),每次select之前从rbtree/堆里边取出一个将近超时的节点;放到 select就可以了,select返回后要么是超时(从rbtree/堆中取出所有超时节点,回调),要么是socket通知(回调读写函数);这样既可以实现timeout回调和socket通知。
作者: robin10    时间: 2011-01-12 02:11
成熟的网络库一般都集成定时器回调和socket通知,大致上都是底层挂一个rbtree或者堆(里边的节点是按照时间 ...
iccc11 发表于 2011-01-11 21:10



先谢谢~  
我有点看不懂,可能比较深奥或者我不太熟悉这方面。
晚上看到网上有人用链表,而BTree之类的做定时器,没有仔细看。不清楚是否和XD说的类似。。?
说说我的环境,arm-linux  kernel 2.6.13,估计除了libc.so libc++.so 和系统调用,我没有太多的其他选择,或者有我没有用过。。。。
最可恶的连glibc 都没有。。。当然,我可以放一个进去,不过为了一个定时器,肯定不值得这样做。

也就是说,我应该没拥有你说的“成熟的网络库”?

另一方面,是因为我使用了signal(),导致了select()的TIMEOUT。
这是否就意味着,我不可以2者同时使用?
作者: drangon    时间: 2011-01-12 08:47
最好别用signal,特别是在多线程环境下,这个东西要用好太麻烦了。

开一个线程来做定时器没什么复杂吧,只多一个线程应该是可以接受的,又不需要每个定时器单独开线程的

如果你定时器数量不多,就简单一个数组或者链表就行了,没必要用到复杂的rbtree,等到profile发现这里是性能瓶颈的时候再优化都来得及。
作者: iccc11    时间: 2011-01-12 09:13
回复 13# robin10


    我说网络库的意思是你自己可以参考一下libevent里边的实现,不是说直接用;自己写一个可能也只需要一天的时间吧。
作者: robin10    时间: 2011-01-12 10:30
最好别用signal,特别是在多线程环境下,这个东西要用好太麻烦了。

开一个线程来做定时器没什么复杂吧, ...
drangon 发表于 2011-01-12 08:47



   恩,是的,我已经决定开条线程来做了,不过开一个线程只是做了个定时器,感觉有点没必要了。。。。呵呵。。。。
而且后面可能会涉及到访问的数据是否同步的问题。。

我的初衷是可以有更加方便的解决方法。。。都怪那该死的glibc 太好用了:)
另外一方面是,我之前不知道,signal()和select()之间(可能)会存在这样的冲突。。。所以想大家讨论讨论,有没有更加好的解决方法。。。
非常感谢!
作者: robin10    时间: 2011-01-12 10:51
回复  robin10


    我说网络库的意思是你自己可以参考一下libevent里边的实现,不是说直接用;自己写 ...
iccc11 发表于 2011-01-12 09:13



    WOW,这个对我来说,可能有点困难~~我自己没有试过这样的做法~
不排除有空的话,自己会写这样一个东西测试一下。。。。


PS.昨天想到了一个比较BT的方法~~哈哈,当然,现实中估计没人愿意这样做--除非是不得已、时间要求很严格什么的。。。。
不过,仍然是一个解决方案!当是一种可行方案讨论一下,还是值得的。

使用芯片的Timer计时,这样可能有需要累加之类的。。。毕竟芯片的 Timer的频率比较高,我们一般不需要这样小间隔的定时器。。。

哈哈,不知道那位DX有试过,在有OS的情况下,用硬件定时器来给应用程序做定时器呢?
我相信这个做法会很准确。。。。
作者: drangon    时间: 2011-01-12 10:54
不是glibc,是glib,这两个东西差别很大的,

glib里面的timer其实也是一样的原理,只不过没有开单独线程,而是在主线程的main loop里面定期检查timeout而已。

你如果不开线程,把自己的主线程做成event loop,定期处理timeout也是可以的

这个东西看看代码其实也没什么特别,要做一个大而全的象glib这样的库可能工作量较大,
但只实现自己需要的功能的话,其实也没多少工作量,没必要羡慕glib,学习吸收一下就行了
作者: robin10    时间: 2011-01-12 11:15
不是glibc,是glib,这两个东西差别很大的,

glib里面的timer其实也是一样的原理,只不过没有开单独线程 ...
drangon 发表于 2011-01-12 10:54



    恩,其实我猜 glib也是按照这个原理做的,虽然我没有读过它们的实现代码。。
因为如果系统只提供setitimer()等几个定时器的接口,
那么估计上面的lib也逃离不了,或者说,它们应该也不会去用一些比较麻烦的方法实现。。。(不过我的确不太清楚glib/glibc的区别,有空了解一下)

不过仍然有一个疑问,假设glib是用信号ITIMER_REAL实现计时的,那么,为什么我同时使用g_timeout_add() and select() (假设前者的TIMEOUT比后者的小),
而没有遇到select()没有到达设定时间就出现了TIMEOUT的情况??

希望可以指点一下。

谢谢~
作者: robin10    时间: 2011-01-12 11:26
http://en.wikipedia.org/wiki/GNU_C_Library

感谢 drangon的指正~
关于 glib and glibc 的一些描述。需要了解的童鞋可以看看~
作者: ecjtubaowp    时间: 2011-01-12 12:21
linux rtc
作者: robin10    时间: 2011-01-12 14:11
linux rtc
ecjtubaowp 发表于 2011-01-12 12:21



    如果用这个做。。MS每次都是要从新设置。。。这个有点像setitimer()?

问题在于,在timeout 之前,是block的,在系统和APP还需要正常跑的情况下,当然不太希望这样了。
作者: robin10    时间: 2011-01-12 14:21
这个好像和之前提到的硬件Timer是一样或者类似的。。。
如果可以修改一下。。响应callback? MS还是不错的。。
作者: 一介村夫    时间: 2011-01-23 21:35
select被信号中断与超时的返回值是不同的。
作者: kuok2000    时间: 2011-01-24 13:34
你可以在select函数返回后判断错误码与返回值,通过返回你应该可以知道函数是如何被终止。如果是被信号打断则可以重新计时。
作者: johntsu    时间: 2011-01-30 14:50

作者: robin10    时间: 2011-03-03 09:26
select被信号中断与超时的返回值是不同的。
一介村夫 发表于 2011-01-23 21:35


这个没有注意到。。。不过SELECT() TIMEOUT了。。。
作者: robin10    时间: 2011-03-03 09:39
你可以在select函数返回后判断错误码与返回值,通过返回你应该可以知道函数是如何被终止。如果是被信号打断 ...
kuok2000 发表于 2011-01-24 13:34


这个。。。好像会比较痛苦吧。。。
比如说,我要读一个服务器的返回内容,TIMEOUT=120S,
而我的SIGNAL 是1S 一次的。。。。。

那么在最坏的情况下。。。我是否要在SELECT中 重复开始计时 120次左右(?)。。
另外,这种情况下,我还得知道,我之前一共耗掉了多少时间。

否则,最坏的情况下,如果我SELECT的返回一直都是超过 1S,那么我的SELECT()将永远无法退出(?,假设下一个SIGNAL会在SELECT 返回之前)
(因为 SIGNAL是1S,这个是一直都有的,如果SELECT()在1S内无法返回,那么就会得到SIGNAL退出。。。而且一直会循环下去(?))

哈哈,当然,这些可能都只是极端情况。



不知道比较 “正规”的做法是怎么样的?

PS,我已经另外开一条线程来实现计时了。。。。
不过一样很欢迎大家可以讨论这个问题。
并感谢所有回帖的XDJM。
作者: giantchen    时间: 2011-03-03 10:55
回复 1# robin10


    http://blog.csdn.net/Solstice/archive/2011/02/06/6173563.aspx
作者: robin10    时间: 2011-03-03 11:39
回复 29# giantchen


新的   Reactor 模式 ?

看了一下链接。。。
牛人。。。看的还不是很理解。。。收藏回头慢慢看~

谢了。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2