要在多线程里面延时1S sleep 好像不是安全的

183 views
Skip to first unread message

papamms

unread,
May 8, 2006, 3:43:17 AM5/8/06
to 高性能网络编程邮件列表
c 来写的 应该用什么好?
ace 里面有吗? 线程安全吗?

Stone Jiang

unread,
May 8, 2006, 4:03:26 AM5/8/06
to dev4s...@googlegroups.com
什么是"线程不安全"哦?
sleep()不与线程中的资源访问重突,怎么会不安全呢?

 
On 5/8/06, papamms <ppms...@gmail.com> wrote:
c 来写的  应该用什么好?
ace 里面有吗? 线程安全吗?




--
Take care
Stone Jiang

清风雨

unread,
May 8, 2006, 4:08:22 AM5/8/06
to 高性能网络编程邮件列表
为什么认为sleep不安全?
不过,这1s是不是太长了?

WaitFor也同样会挂起线程,而且1ms的睡眠并不影响你的响应。考虑网络延时一般都是100ms到600ms,对比一下,真的是无所谓,反而更处其它处理更多的CPU机会和时间。

至于线程安全问题,这个和是否睡眠没有关系。是多线程竞争资源必须做的工作。(不过,对于多线程,推荐如果不是很了解,还是不要乱用的好;当然,用的好,可以获得很多好处。)

Stone Jiang

unread,
May 8, 2006, 4:13:18 AM5/8/06
to dev4s...@googlegroups.com
ACE中写sleep()的语句是这样的
ACE_Time_Value tv(1,0); 
ACE::sleep(tv);

清风雨

unread,
May 8, 2006, 4:36:23 AM5/8/06
to 高性能网络编程邮件列表
谢谢!
虽然,我对这种对底层API简单封装的,一般都不是很感兴趣。
不过,听说ACE的架构不错,什么时候有空,会去学习一下。

说真的,我看不出这个ACE封装相对API有什么好处(反而是更低效),winAPI是Sleep(
unsingned ms ),unix系(包括linux)的是sleep( unsingned
ms,unsigned us
)(这里unsigned记得不是很确切,也可能是int,如果是int,我到觉得他应该是unsigned的好)

ppmsn2005

unread,
May 8, 2006, 4:28:25 AM5/8/06
to dev4s...@googlegroups.com
sleep 有文献能证明它是线程安全的吗?
不能证明 当然会有危害行
我要sleep 自然是业务逻辑上需要。 网络延迟 靠sleep ??

异步拿来干什么?

ppmsn2005

unread,
May 8, 2006, 4:30:05 AM5/8/06
to dev4s...@googlegroups.com
因为如果多个线程都要sleep 1s 的话 是否线程安全很重要 不安全 时间可能不对
----- Original Message -----
Sent: Monday, May 08, 2006 4:03 PM
Subject: Re: 要在多线程里面延时1S sleep 好像不是安全的

sunway

unread,
May 8, 2006, 5:04:00 AM5/8/06
to 高性能网络编程邮件列表
win32下sleep的误差在15毫秒左右。
不建议在主要的业务逻辑中使用sleep,这样严重的影响性能。
我一般在线程关闭或者线程启动的代码里使用sleep

Stone Jiang

unread,
May 8, 2006, 5:05:59 AM5/8/06
to dev4s...@googlegroups.com
hi,清风雨

正如你说的那样,ACE对这类API的封装反而会更低效--至少多一次函数调用的开销。
 
但它的好处也从你自己的邮件中反映出来了,它利用设计模式中的Facade模式,能使客户(程序员)看不异种环境下的差异,从而写出更不容易出错的代码。就像你可能记不清某一平台下的api函数的参数,可能因为误用而超成问题,解决这个问题可能带来更多的投入。
 

 
On 5/8/06, 清风雨 <zhang...@gmail.com> wrote:

清风雨

unread,
May 8, 2006, 6:24:52 AM5/8/06
to 高性能网络编程邮件列表
我不认为这种肤浅的封装有任何意义。虽然,他确实夸平台有点用。
但对我来说没有任何意义,如果谈夸平台,我宁愿选择java,或者我自己封装
—— 至少针对我特殊的需求更适应。

你谈的是Facade的好处,而不是肤浅封装的好处。

我想用ACE的程序员,恐怕不会对win或linux平台有所了解,至少他会熟悉其中之一,而熟悉之一,再熟悉另一,我看ACE这个API封装没有带来什么优势——
至少肤浅的封装他不应该企图去做一个无效的转换。

请注意,我只是谈ACE这个API的封装设计。——
至少,这个API,我不敢苟同他的设计。

清风雨

unread,
May 8, 2006, 6:25:41 AM5/8/06
to 高性能网络编程邮件列表
同步你能Sleep,那真是...... ^_^

清风雨

unread,
May 8, 2006, 6:26:53 AM5/8/06
to 高性能网络编程邮件列表
同步你能Sleep,那真是...... ^_^

清风雨

unread,
May 8, 2006, 6:30:02 AM5/8/06
to 高性能网络编程邮件列表
第一次听说精度在15毫秒!:}
能不能给出证明,我也好受教!

至于一般的说法,我想搁下看来从来不浪费CPU资源的了,没事空转也要让他100%,还好微软MFC做了些工作。我真怀疑,我机器除了跑搁下的程序,会什么事都不能做了。

清风雨

unread,
May 8, 2006, 6:32:40 AM5/8/06
to 高性能网络编程邮件列表
顺便不给面子一次(^_^)。恕我直言,请阁下先搞定什么是线程安全,什么是延时,什么是同步,什么是异步,还有我说了什么。

sunway

unread,
May 8, 2006, 7:22:00 AM5/8/06
to 高性能网络编程邮件列表
你可以用GetTickCount()测试以下一个比较消耗时间的函数运行时间,
要么是0要么就是16偶尔有15出现.所以精度大致在15毫秒。

HuYi

unread,
May 8, 2006, 8:47:05 PM5/8/06
to dev4s...@googlegroups.com
ACE并不限制用户采用不封装的用户。
它对原生API的封装只是提供给有跨平台需要的那部分特殊用户而已。
与其自己再封装一个,不如用它提供的。

清风雨

unread,
May 8, 2006, 9:18:55 PM5/8/06
to 高性能网络编程邮件列表
所以你搞错了。
GetTickCount的精度是10ms,但是Sleep和GetTickCount不是一回事。

如果要获取精确的时间用timeGetTime(可以精确到ms)或QueryPerfermanceCounter

sunway

unread,
May 8, 2006, 9:23:16 PM5/8/06
to 高性能网络编程邮件列表
GetTickCount实际测试结果是15~16ms,而且sleep的精度测试如果用GetTickCount来做的话
精度也只有15~16ms,通过这个可以看出sleep的精度不高,所以我有理由相信sleep的精度也在
15~16ms之间。

清风雨

unread,
May 8, 2006, 9:23:49 PM5/8/06
to 高性能网络编程邮件列表
这个不一定,因为这个sleep根本就是没有封装的封装。
自己用#ifdef 比用它都来的快。

请注意,我只是看到了这个sleep的封装,不太赞同。别的封装,因为并不太了解,也不敢多言。

或许,他的整体设计需求,这样封装,符合他的整体性,那么,也就是说他的这个整体封装设计思路还不够好。


至于性能,多以个调用开销,倒也没什么。
主要是构造、析构、copy构造、析构。即使编译器为你优化,也还是有至少一次构造、析构。

清风雨

unread,
May 8, 2006, 9:25:33 PM5/8/06
to 高性能网络编程邮件列表
小伙子。 我只能告诉你这么多了。
你还要这么认为,而且不去查查资料和试验一下,那我就没有办法了。

papamms

unread,
May 8, 2006, 10:05:30 PM5/8/06
to 高性能网络编程邮件列表
卖什么老啊

看你的回答 基本能明白你的水平

HuYi

unread,
May 8, 2006, 10:17:31 PM5/8/06
to dev4s...@googlegroups.com
ACE对原生API的封装支持,好像并不需要每次调用前都构建一个对象实例。
以下是ACE封装sleep的代码,既然大家觉得不够好,那看看怎么改进比较好一些。
如果非要把函数调用归为性能瓶颈一类,似乎ACE已经靠内联把这个“瓶颈”消除
了,除了换来和手工调用sleep产生相同的代码段,也换来了在不同平台下相同的
使用方式。
大家的意见呢?

00999 ACE_INLINE int
01000 ACE_OS::sleep (u_int seconds)
01001 {
01002 ACE_OS_TRACE ("ACE_OS::sleep");
01003 #if defined (ACE_WIN32)
01004 ::Sleep (seconds * ACE_ONE_SECOND_IN_MSECS);
01005 return 0;
01006 #if 0
01007 #elif defined (HPUX_10) && defined (ACE_HAS_PTHREADS_DRAFT4)
01008 // On HP-UX 10, _CMA_NOWRAPPERS_ disables the mapping from sleep
to cma_sleep
01009 // which makes sleep() put the whole process to sleep, and keeps
it from
01010 // noticing pending cancels. So, in this case, use pthread_delay_np
01011 struct timespec rqtp;
01012 rqtp.tv_sec = seconds;
01013 rqtp.tv_nsec = 0L;
01014 return pthread_delay_np (&rqtp);
01015 #endif /* 0 */
01016 #elif defined (ACE_HAS_CLOCK_GETTIME)
01017 struct timespec rqtp;
01018 // Initializer doesn't work with Green Hills 1.8.7
01019 rqtp.tv_sec = seconds;
01020 rqtp.tv_nsec = 0L;
01021 ACE_OSCALL_RETURN (::nanosleep (&rqtp, 0), int, -1);
01022 #elif defined (ACE_PSOS)
01023 timeval wait;
01024 wait.tv_sec = seconds;
01025 wait.tv_usec = 0;
01026 ACE_OSCALL_RETURN (::select (0, 0, 0, 0, &wait), int, -1);
01027 #else
01028 ACE_OSCALL_RETURN (::sleep (seconds), int, -1);
01029 #endif /* ACE_WIN32 */
01030 }
01031
01032 ACE_INLINE int
01033 ACE_OS::sleep (const ACE_Time_Value &tv)
01034 {
01035 ACE_OS_TRACE ("ACE_OS::sleep");
01036 #if defined (ACE_WIN32)
01037 ::Sleep (tv.msec ());
01038 return 0;
01039 #else
01040 # if defined (ACE_HAS_NONCONST_SELECT_TIMEVAL)
01041 // Copy the timeval, because this platform doesn't declare the
timeval
01042 // as a pointer to const.
01043 timeval tv_copy = tv;
01044 ACE_OSCALL_RETURN (::select (0, 0, 0, 0, &tv_copy), int, -1);
01045 # else /* ! ACE_HAS_NONCONST_SELECT_TIMEVAL */
01046 const timeval *tvp = tv;
01047 ACE_OSCALL_RETURN (::select (0, 0, 0, 0, tvp), int, -1);
01048 # endif /* ACE_HAS_NONCONST_SELECT_TIMEVAL */
01049 #endif /* ACE_WIN32 */
01050 }

sunway

unread,
May 8, 2006, 10:23:21 PM5/8/06
to 高性能网络编程邮件列表
我已经说过了,我实际测试过的,而且其他同事也做过类似的测试,结果基本上就是我说的。

清风雨

unread,
May 8, 2006, 11:02:44 PM5/8/06
to 高性能网络编程邮件列表
是嘛? 那我也试试看。
我以前试过感觉好像是很准确的啊。
等会,我把测试结果贴过来。

清风雨

unread,
May 8, 2006, 11:16:24 PM5/8/06
to 高性能网络编程邮件列表
1.
inline在VC编译器上,只是一个建议标识,编译器不一定会inline
2.
我蛮奇怪的,为什么他第一个要用s而不要ms呢?平台API都是基于ms的。
3. 你用的const ACE_Time_Value
&tv和前面那位仁兄贴的不太一样吧!
4. ACE_Time_Value
是一个struct吧?C++里,这个struct的生成是有构造开销的(可能他这里什么都没做)。
5. 他为什么要提供select阻塞的呢?蛮奇怪的。

6.
严格来说,因为是sleep,所以这里的函数调用开销是可以忽略的,没有任何的所谓性能影响,但,它形成的是一种不好习惯和对性能问题的忽视——
有些时候是可以需要在意的。
7. 不是大家觉得不够好,是我个人觉得(^_^)。
8.
头文件里包含代码和一堆宏,确实是比较的麻烦。比如STLport的STL实现,虽然号称是可读性最好的,但是,读取来是相当痛苦的事。
9. 我倾向第一个提供方式,因为概念更少。
第二个引入了一个中间概念(本身可以对用户忽略的概念)。

清风雨

unread,
May 8, 2006, 11:22:14 PM5/8/06
to 高性能网络编程邮件列表
看来搁下对我的方式很为不满。
不过,搁下对我这个态度,我还偏要对你这个态度。

我水平是也很一般,这个不瞒你说,我自己知道。

说真的,我对sunway的说法只不过是加重语气、强调罢了,如果是本人觉得郁闷,我也可以理解和接受。而偏偏搁下这个,我就很为反感了。——
还好,我们不需要成为朋友。

以前,对这种郁闷惯了,置之不理。但我本来就是小心眼的人,对这种人,今天,我就偏不客气了。

清风雨

unread,
May 8, 2006, 11:40:07 PM5/8/06
to 高性能网络编程邮件列表
代码如下:
#include <iostream>

#include <windows.h>

#pragma comment( lib,"winmm" )

int main( int argc,char *argv[] )
{
timeBeginPeriod( 1 );
::Sleep( 100 );

for ( int i = 0; i < 10; ++i )
{
unsigned start = timeGetTime();
::Sleep( 1 );
unsigned end = timeGetTime();
std::cout << "time elapsed : " << end - start << std::endl;
}
timeEndPeriod( 1 );

return 0;
}


运行一下,我机器上(win2K),结果显示是:
time elapsed : 2
time elapsed : 2
time elapsed : 2
time elapsed : 2
time elapsed : 2
time elapsed : 2
time elapsed : 2
time elapsed : 2
time elapsed : 2
time elapsed : 2

不过,有的时候确实会上16ms,这个是平均结果。

HuYi

unread,
May 8, 2006, 11:59:32 PM5/8/06
to dev4s...@googlegroups.com
1。虽然很多书上都这么说:inline只是给编译器的建议。但确实大多数情况下
inline的效果都达到了,不嫌麻烦的话,可以跟踪一下。至于什么时候编译器看到
inline建议,但是不采用inline的做法,希望有达人能解释一下,并说明一下编译
器这么做的利弊是什么。
2。可能是你工作的平台API是基于ms的吧,因为是ms的平台:)
Linux下可不是这样,高精度的是另外一个函数nanosleep来实现的。ACE按照Linux
的做法把它们分开了。所以还提供了一个 nanosleep函数。
3。可能我和他源码版本不同造成的,我的是5.4
4。一秒钟能掉几次sleep?这种都要算作性能瓶颈的理由,太牵强了。难道真的要
回归c的时代。c里面也用struct:)
5。这个问题的重点在于ACE_PSOS的定义,我没有用过这方面的东西,懂得人请站
出来解释一下。个人猜测可能是在那个平台或者环境下面没有合适的 sleep,所以
简单的模拟一下。

sunway

unread,
May 9, 2006, 12:18:23 AM5/9/06
to 高性能网络编程邮件列表
我测试使用GetTickCount(),Sleep(1)基本每次都是15ms~16ms,
你也承认过有的时候确实会上16ms,说明精度确实不够,最差的精度
就是15~16ms.

清风雨

unread,
May 9, 2006, 12:31:09 AM5/9/06
to 高性能网络编程邮件列表
不说,我一直以为它不会超出1ms的,一测试,反而更明确和清楚。
不过,MSDN是说它至少睡眠1ms,也就是说可以超出1ms。

GetTickCount的精度只有10ms,如果要获得更精确的时间,还是不能用它的。

清风雨

unread,
May 9, 2006, 12:48:56 AM5/9/06
to 高性能网络编程邮件列表
那即使提供nanosleep和sleep也不要紧,你给的那个封装,我确实发现不了它相对任何一个平台API能带来的好处。

inline为什么不inline,是因为
1. virtual 函数无法inline
2.
inline可能使得代码量增大,从而导致CPU缓存丢失,反而降低性能
—— 比如,一般对循环的inline都会被忽略。
3.
inline本来就是为了速度考虑,所以,MS选择不一定给予inline,因为它不一定能提高性能。——
这个是我想MS这么做的原因。

我的工作的平台确实是win,而且我本人对linux也不怎么了解。

我想他的版本应该比你高,因为做为const
&好像很应该也很正常。

当然,我知道linux下也有个struct的sleep版本,你不觉得ACE这样没有对你屏蔽底层平台吗?而是每个平台提供了一套方案。还好他们的原理都一直,所以理解起来并不是很困难。既然这样,为什么不直接学习平台API呢(和你学习ACE的代价等同了,我指这个API封装)?而且你可以定制你自己的需求(而ACE这里相对定制能力就要差一些了)。

清风雨

unread,
May 9, 2006, 12:59:14 AM5/9/06
to 高性能网络编程邮件列表
我并不关心ACE内部怎么实现(需要学习借鉴的时候再说),我只关心它给我提供的API,而这么多贴下来,反而,更能说明问题:它并没有简化问题。

而是复杂化了问题。难道,你提供封装接口是这样提供的?你赞同这样做?如果你回答肯定,...
;如果否定,我要表达的意思已经很明确 ——
为什么我觉得它这里不好(或不够好)。

sunway

unread,
May 9, 2006, 1:03:26 AM5/9/06
to 高性能网络编程邮件列表
总之sleep精度不够,GetTickCount的精度应该是15~16ms左右,而不是资料上的10ms。Sleep在关键的业务逻辑中使用并不是很可靠。尤其是在服务器端的关键业务逻辑中使用。

HuYi

unread,
May 9, 2006, 1:12:01 AM5/9/06
to dev4s...@googlegroups.com
1.这里用了虚函数了吗?如果没有,那它凭什么不inline?
2。那define就不会加大体积吗?
3。你一直觉得自己做的比ACE好,借用以前一个朋友说过的一句话,把你的代码提
交给ACE,为广大的程序员朋友们造福。

清风雨

unread,
May 9, 2006, 1:57:00 AM5/9/06
to 高性能网络编程邮件列表
1.
你先搞清楚,我说的针对特定的一个问题。而且,也没有否定ACE的工作和成果。

2. 还有,我只是顺便帮你解释为什么inline只是建议。

3. #define
和inline根本就不是一回事,inline不等于#define,这个我就不多说了。

4. 我要表达的都写的清清楚楚,已经没什么好说的。

5.
我不是要和你争论个什么结论出来,我只是顺便,给些值得参考的意见罢了。你听的进就听,听不进就不听。

6.
我还并没有说我比ACE做的好,你要搞清楚,我每处的表述。——
和fans们说话,就是累。就如我会情绪化一样,我也很理解fans们的情绪化。

7.
好了,我不多说了。不过,你贴出来的ACE代码,写的还不错。感谢你告诉了我linux下有nanosleep等。

Message has been deleted

Darwin Lalo

unread,
May 10, 2006, 4:45:22 AM5/10/06
to 高性能网络编程邮件列表
不好意思,我的代码有问题,呵呵,的确是 10+ ms 左右

Darwin Lalo 写道:

> 谁说的,晕
> 你们自己运行看看
>
> DWORD tc[100];
> for(int i = 0; i < sizeof(tc)/sizeof(DWORD); ++i){
> tc[i] = GetTickCount();
> }
>
> for(int i = 0; i < sizeof(tc)/sizeof(DWORD); ++i){
> printf("%d\n", tc[i]);
> }
>
>
> sleep(1) 不可靠,我认可,但是。。。
>
> 要想搞清楚这个问题,请看看 操作系统->调度算法
> windows 的时间片轮转 什么的
>
>
> sunway 写道:

Lee Alvin

unread,
May 10, 2006, 5:41:58 AM5/10/06
to dev4s...@googlegroups.com
2006/5/8, 清风雨 <zhang...@gmail.com>:

> 我不认为这种肤浅的封装有任何意义。虽然,他确实夸平台有点用。
> 但对我来说没有任何意义,如果谈夸平台,我宁愿选择java,或者我自己封装

java的效率会比c/c++的程序慢一倍,这个还算是很理想的数据,但是如果是高负载高能服务器,你不见得能把硬件的档次提高一倍。更何况java的NIO低层目前也都还没有能力粘和IOCP和POSIX
AIO,定多就是select和epoll在5.0的版本里。

> —— 至少针对我特殊的需求更适应。
>
> 你谈的是Facade的好处,而不是肤浅封装的好处。
>
> 我想用ACE的程序员,恐怕不会对win或linux平台有所了解,至少他会熟悉其中之一,而熟悉之一,再熟悉另一,我看ACE这个API封装没有带来什么优势——
> 至少肤浅的封装他不应该企图去做一个无效的转换。
>
> 请注意,我只是谈ACE这个API的封装设计。——
> 至少,这个API,我不敢苟同他的设计。

如果你做跨平台的高能服务器,或者框架,请给出你的设计和思路?

>
> >
>


--
Enjoy your life! Make things clearly and easier!
Reply Mailto: alvi...@gmail.com
My Blog: http://wolf.bloghome.cn

Lee Alvin

unread,
May 10, 2006, 5:48:14 AM5/10/06
to dev4s...@googlegroups.com
2006/5/8, 清风雨 <zhang...@gmail.com>:
> 第一次听说精度在15毫秒!:}
> 能不能给出证明,我也好受教!

请看《Windows核心编程》里面介绍线程切换的章节讲的很清楚,由于NT内核系统并不是设计为实时操作系统,线程调度的时间精度是30ms。

>
> 至于一般的说法,我想搁下看来从来不浪费CPU资源的了,没事空转也要让他100%,还好微软MFC做了些工作。我真怀疑,我机器除了跑搁下的程序,会什么事都不能做了。

Lee Alvin

unread,
May 10, 2006, 5:53:53 AM5/10/06
to dev4s...@googlegroups.com
2006/5/8, 清风雨 <zhang...@gmail.com>:
> 顺便不给面子一次(^_^)。恕我直言,请阁下先搞定什么是线程安全,什么是延时,什么是同步,什么是异步,还有我说了什么。

这就是你的不对了,就算他不知道,你就不能讲解出来,更何况自己都搞清除了没?还就是只搞清楚了MFC的那点封装类,更何况其他平台以及操作系统理论。

Lee Alvin

unread,
May 10, 2006, 6:10:24 AM5/10/06
to dev4s...@googlegroups.com
2006/5/9, 清风雨 <zhang...@gmail.com>:

> 这个不一定,因为这个sleep根本就是没有封装的封装。
> 自己用#ifdef 比用它都来的快。
>
> 请注意,我只是看到了这个sleep的封装,不太赞同。别的封装,因为并不太了解,也不敢多言。

就ACE_Time_Value不光是只给sleep用的,ACE中的时间和超时操作基本上都是依赖于
它的,想想Timer,IO超时吧。

>
> 或许,他的整体设计需求,这样封装,符合他的整体性,那么,也就是说他的这个整体封装设计思路还不够好。
>
>
> 至于性能,多以个调用开销,倒也没什么。
> 主要是构造、析构、copy构造、析构。即使编译器为你优化,也还是有至少一次构造、析构。

ACE_Time_Value和《C++对象模型》你都仔细看了吗?还只是略知皮毛?ACE的ACE_Time_Value根本就是个POD,你要要觉得效率低,那直接使用memcpy好了。关于构造,你也说了多个调用开销也没什么,如果真是C++加上的"无用"的空构造和析构,就算调用一下也如你说的没什么,更何况空调用会被编译器优化掉。另外,就算是操作系统提供的时间结构,你不也要使用memset初始化一下的。

Lee Alvin

unread,
May 10, 2006, 6:24:37 AM5/10/06
to dev4s...@googlegroups.com
2006/5/9, 清风雨 <zhang...@gmail.com>:

> 1.
> inline在VC编译器上,只是一个建议标识,编译器不一定会inline
> 2.
> 我蛮奇怪的,为什么他第一个要用s而不要ms呢?平台API都是基于ms的。

有二个参数,一个是秒,另外一个是毫秒,这样使用起来方便。而不是在使用秒的时候给一个巨大的数字。

> 3. 你用的const ACE_Time_Value
> &tv和前面那位仁兄贴的不太一样吧!
> 4. ACE_Time_Value
> 是一个struct吧?C++里,这个struct的生成是有构造开销的(可能他这里什么都没做)。

错了,是class,你前面和后面也说了,函数调用开销是可以忽略,那在乎一个构造的函数调用有什么意义。


> 5. 他为什么要提供select阻塞的呢?蛮奇怪的。

在win32下是sleep,在其他平台是用select的超时做的。

>
> 6.
> 严格来说,因为是sleep,所以这里的函数调用开销是可以忽略的,没有任何的所谓性能影响,但,它形成的是一种不好习惯和对性能问题的忽视——
> 有些时候是可以需要在意的。
> 7. 不是大家觉得不够好,是我个人觉得(^_^)。
> 8.
> 头文件里包含代码和一堆宏,确实是比较的麻烦。比如STLport的STL实现,虽然号称是可读性最好的,但是,读取来是相当痛苦的事。
> 9. 我倾向第一个提供方式,因为概念更少。
> 第二个引入了一个中间概念(本身可以对用户忽略的概念)。
>
> >
>

Lee Alvin

unread,
May 10, 2006, 6:29:04 AM5/10/06
to dev4s...@googlegroups.com
2006/5/9, HuYi <hu...@dl.necsl.com.cn>:

>
> 清风雨 wrote:
> > 1.
> > inline在VC编译器上,只是一个建议标识,编译器不一定会inline
> > 2.
> > 我蛮奇怪的,为什么他第一个要用s而不要ms呢?平台API都是基于ms的。
> > 3. 你用的const ACE_Time_Value
> > &tv和前面那位仁兄贴的不太一样吧!
> > 4. ACE_Time_Value
> > 是一个struct吧?C++里,这个struct的生成是有构造开销的(可能他这里什么都没做)。
> > 5. 他为什么要提供select阻塞的呢?蛮奇怪的。
> >
> > 6.
> > 严格来说,因为是sleep,所以这里的函数调用开销是可以忽略的,没有任何的所谓性能影响,但,它形成的是一种不好习惯和对性能问题的忽视——
> > 有些时候是可以需要在意的。
> > 7. 不是大家觉得不够好,是我个人觉得(^_^)。
> > 8.
> > 头文件里包含代码和一堆宏,确实是比较的麻烦。比如STLport的STL实现,虽然号称是可读性最好的,但是,读取来是相当痛苦的事。
> > 9. 我倾向第一个提供方式,因为概念更少。
> > 第二个引入了一个中间概念(本身可以对用户忽略的概念)。
> >
> > >
> >
> 1。虽然很多书上都这么说:inline只是给编译器的建议。但确实大多数情况下
> inline的效果都达到了,不嫌麻烦的话,可以跟踪一下。至于什么时候编译器看到
> inline建议,但是不采用inline的做法,希望有达人能解释一下,并说明一下编译
> 器这么做的利弊是什么。

这个《c++对象模型》上应该是可以査到的。

> 2。可能是你工作的平台API是基于ms的吧,因为是ms的平台:)
> Linux下可不是这样,高精度的是另外一个函数nanosleep来实现的。ACE按照Linux
> 的做法把它们分开了。所以还提供了一个 nanosleep函数。
> 3。可能我和他源码版本不同造成的,我的是5.4
> 4。一秒钟能掉几次sleep?这种都要算作性能瓶颈的理由,太牵强了。难道真的要
> 回归c的时代。c里面也用struct:)
> 5。这个问题的重点在于ACE_PSOS的定义,我没有用过这方面的东西,懂得人请站
> 出来解释一下。个人猜测可能是在那个平台或者环境下面没有合适的 sleep,所以
> 简单的模拟一下。

我也是这么想的,用超时来模拟。

Lee Alvin

unread,
May 10, 2006, 6:37:24 AM5/10/06
to dev4s...@googlegroups.com
2006/5/9, 清风雨 <zhang...@gmail.com>:

> 我并不关心ACE内部怎么实现(需要学习借鉴的时候再说),我只关心它给我提供的API,而这么多贴下来,反而,更能说明问题:它并没有简化问题。

ACE有几个层次,ACE_OS::sleep只是OS API的屏蔽层,那上面的框架层,服务层,按你这么说就用OS
API的屏蔽层就能说明上面主要层次的问题了吗?更何况,ACE主要的用途也就是框架层和服务层。当你要使用API时,要屏蔽操作系统差异时,也可以用它为你准备好的ACE_OS层的API,那样不更方便,更何况可以和框架保良好的统一,不是吗?更妙的时候它能够很好的和框架的对象交互。何乐而不为?

>
> 而是复杂化了问题。难道,你提供封装接口是这样提供的?你赞同这样做?如果你回答肯定,...
> ;如果否定,我要表达的意思已经很明确 ——
> 为什么我觉得它这里不好(或不够好)。
>
> >
>

Lee Alvin

unread,
May 10, 2006, 6:43:59 AM5/10/06
to dev4s...@googlegroups.com
其实,大家没什么好吵和攻击的,人非圣贤,都可能犯错误或者片面的下结论。也不排除不打不相识的可能,特别是有性格和个性的牛人,或者想成为牛人的。

2006/5/9, 清风雨 <zhang...@gmail.com>:

phus

unread,
May 10, 2006, 7:11:11 AM5/10/06
to 高性能网络编程邮件列表
为 Lee Alvin 喝彩.
有理有节, 可作为此贴的盖棺定论了.

清风雨

unread,
May 10, 2006, 8:31:17 AM5/10/06
to 高性能网络编程邮件列表
我不想和你多说什么,你先搞清楚在说什么。
不过,不能忘了告诉你,我不用MFC,而且我也不喜欢MFC的设计。

清风雨

unread,
May 10, 2006, 8:33:52 AM5/10/06
to 高性能网络编程邮件列表
我想你先搞清楚,我说的什么,我在说什么。

你不要把你的以为的盖到我头上,我本来是不想和你们多说什么了。因为,我发现,一路在歪曲我的意思。

清风雨

unread,
May 10, 2006, 8:36:48 AM5/10/06
to 高性能网络编程邮件列表
先搞清楚了我在说什么,然后再说话。
至于我是不是片面,阁下还不够水准(恕我直言)。

清风雨

unread,
May 10, 2006, 8:39:58 AM5/10/06
to 高性能网络编程邮件列表
我想你其实可以认真看看,我在说什么。——
太多了,要看清楚可能还比较麻烦的。
如果,你是对技术有兴趣,而不是做盲从者。

清风雨

unread,
May 10, 2006, 8:42:33 AM5/10/06
to 高性能网络编程邮件列表
算了,压根就没搞清楚我在说什么。

不是看的书多,理解的就深刻,虽然看书很重要很重要。

Lee Alvin

unread,
May 10, 2006, 9:11:28 AM5/10/06
to dev4s...@googlegroups.com
其实我也不是针对仁兄你,只是看这热闹才来冒个泡,诚心跟大家切磋切磋的。脾气大家都是有的,只是希望大家冷静点,都不要互相伤害和鄙视,真心希望大家共同进步啊。

再则,这个问题二楼本来都说的很清楚了。Sleep本来就是个系统调用,根本都没资源冲突,都谈不上冲突。我认为楼主是想用Sleep来同步资源访问,那肯定是不太可行的方法。这个贴讨论这么多,引入些新的话题,大家讨论下也无妨啊。

你的帖子我都认真看了,都花费了一个小时时间,发表点意见,你不会不接受吧。

Message has been deleted

HuYi

unread,
May 10, 2006, 9:17:18 PM5/10/06
to dev4s...@googlegroups.com
我相信大家都会同意你的说法:不要做盲从者。

最后再补充一点,“封装”并不就等于“低效”,或者是等同于“不如你自己手工编写
的代码”,即使是汇编高手,也不能说自己就比编译器做得好。
正如阁下对ACE中sleep的误解一样。
另外,用MFC开发程序还是很方便的,像vb,拖拖拽拽,补充几个方法也能对付对
付了,比WTL方便。当然,我们组只是用它作一些辅助开发的小工具,并不是做产品。

sunway

unread,
May 11, 2006, 1:55:33 AM5/11/06
to 高性能网络编程邮件列表
其实楼主的这个要求用定时器去解决比较合适,工作线程中一般情况下没有必要用sleep

SevenCat

unread,
May 12, 2006, 8:54:55 PM5/12/06
to 高性能网络编程邮件列表
应该安全,WIN下的SLEEP可能只做两件事:
1、立即把当前线程停掉,线程调度器选下一个线程来运行。
2、增加个内核TIMER,到时间再把你重新加入调度队列(当然里面比较复杂,线程其实还可以被其他的激活,看SleepEx就知道了)

SevenCat

unread,
May 12, 2006, 8:55:24 PM5/12/06
to 高性能网络编程邮件列表
要是高兴的话,我可以把WIN下面Sleep的原代码贴一下。

closeall

unread,
May 13, 2006, 12:56:44 AM5/13/06
to dev4s...@googlegroups.com
to SeverCat:
 
贴出来,学习一下,谢谢

 
On 5/13/06, SevenCat <BastE...@gmail.com> wrote:
要是高兴的话,我可以把WIN下面Sleep的原代码贴一下。




--
Closeall
MSN           : clos...@hotmail.com
Google Talk : closea...@gmail.com

SevenCat

unread,
May 13, 2006, 2:22:06 AM5/13/06
to 高性能网络编程邮件列表
假如我没搞错,可能就是这个了。只是意义似乎不太大。
NTSTATUS
KeDelayExecutionThread (
IN KPROCESSOR_MODE WaitMode,
IN BOOLEAN Alertable,
IN PLARGE_INTEGER Interval
)

/*++

Routine Description:

This function delays the execution of the current thread for the
specified
interval of time.

Arguments:

WaitMode - Supplies the processor mode in which the delay is to
occur.

Alertable - Supplies a boolean value that specifies whether the
delay
is alertable.

Interval - Supplies a pointer to the absolute or relative time over
which
the delay is to occur.

Return Value:

The wait completion status. A value of STATUS_SUCCESS is returned
if
the delay occurred. A value of STATUS_ALERTED is returned if the
wait
was aborted to deliver an alert to the current thread. A value of
STATUS_USER_APC is returned if the wait was aborted to deliver a
user
APC to the current thread.

--*/

{

LARGE_INTEGER DueTime;
LARGE_INTEGER NewTime;
PLARGE_INTEGER OriginalTime;
PKPRCB Prcb;
KPRIORITY Priority;
PRKQUEUE Queue;
PRKTHREAD Thread;
PRKTIMER Timer;
PKWAIT_BLOCK WaitBlock;
NTSTATUS WaitStatus;

//
// If the dispatcher database lock is not already held, then set
the wait
// IRQL and lock the dispatcher database. Else set boolean wait
variable
// to FALSE.
//

Thread = KeGetCurrentThread();
if (Thread->WaitNext) {
Thread->WaitNext = FALSE;

} else {
KiLockDispatcherDatabase(&Thread->WaitIrql);
}

//
// Start of delay loop.
//
// Note this loop is repeated if a kernel APC is delivered in the
middle
// of the delay or a kernel APC is pending on the first attempt
through
// the loop.
//

OriginalTime = Interval;
WaitBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
do {

//
// Test to determine if a kernel APC is pending.
//
// If a kernel APC is pending and the previous IRQL was less
than
// APC_LEVEL, then a kernel APC was queued by another processor
just
// after IRQL was raised to DISPATCH_LEVEL, but before the
dispatcher
// database was locked.
//
// N.B. that this can only happen in a multiprocessor system.
//

if (Thread->ApcState.KernelApcPending && (Thread->WaitIrql <
APC_LEVEL)) {

//
// Unlock the dispatcher database and lower IRQL to its
previous
// value. An APC interrupt will immediately occur which
will result
// in the delivery of the kernel APC if possible.
//

KiUnlockDispatcherDatabase(Thread->WaitIrql);

} else {

//
// Test for alert pending.
//

TestForAlertPending(Alertable);

//
// Initialize wait block, insert wait block in timer wait
list,
// insert timer in timer queue, put thread in wait state,
select
// next thread to execute, and context switch to next
thread.
//
// N.B. The timer wait block is initialized when the
respective
// thread is initialized. Thus the constant fields are
not
// reinitialized. These include the wait object, wait
key,
// wait type, and the wait list entry link pointers.
//

Thread->WaitBlockList = WaitBlock;
Thread->WaitStatus = (NTSTATUS)0;
Timer = &Thread->Timer;
WaitBlock->NextWaitBlock = WaitBlock;
Timer->Header.WaitListHead.Flink =
&WaitBlock->WaitListEntry;
Timer->Header.WaitListHead.Blink =
&WaitBlock->WaitListEntry;

//
// If the timer is inserted in the timer tree, then place
the
// current thread in a wait state. Otherwise, attempt to
force
// the current thread to yield the processor to another
thread.
//
if (KiInsertTreeTimer(Timer, *Interval) == FALSE) {

//
// If the thread is not a realtime thread, then drop
the
// thread priority to the base priority.
//

Prcb = KeGetCurrentPrcb();
Priority = Thread->Priority;
if (Priority < LOW_REALTIME_PRIORITY) {
if (Priority != Thread->BasePriority) {
Thread->PriorityDecrement = 0;
KiSetPriorityThread(Thread,
Thread->BasePriority);
}
}

//
// If a new thread has not been selected, the attempt
to round
// robin the thread with other threads at the same
priority.
//

if (Prcb->NextThread == NULL) {
Prcb->NextThread =
KiFindReadyThread(Thread->NextProcessor,

Thread->Priority);
}

//
// If a new thread has been selected for execution,
then
// switch immediately to the selected thread.
//

if (Prcb->NextThread != NULL) {

//
// Give the current thread a new qunatum and switch
// context to selected thread.
//
// N.B. Control is returned at the original IRQL.
//

Thread->Preempted = FALSE;
Thread->Quantum =
Thread->ApcState.Process->ThreadQuantum;

ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);

KiReadyThread(Thread);
WaitStatus = (NTSTATUS)KiSwapThread();
goto WaitComplete;

} else {
WaitStatus = (NTSTATUS)STATUS_SUCCESS;
break;
}
}

DueTime.QuadPart = Timer->DueTime.QuadPart;

//
// If the current thread is processing a queue entry, then
attempt
// to activate another thread that is blocked on the queue
object.
//

Queue = Thread->Queue;
if (Queue != NULL) {
KiActivateWaiterQueue(Queue);
}

//
// Set the thread wait parameters, set the thread
dispatcher state
// to Waiting, and insert the thread in the wait list.
//

Thread->Alertable = Alertable;
Thread->WaitMode = WaitMode;
Thread->WaitReason = DelayExecution;
Thread->WaitTime= KiQueryLowTickCount();
Thread->State = Waiting;
KiInsertWaitList(WaitMode, Thread);

//
// Switch context to selected thread.
//
// N.B. Control is returned at the original IRQL.
//

ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);

WaitStatus = (NTSTATUS)KiSwapThread();

//
// If the thread was not awakened to deliver a kernel mode
APC,
// then return the wait status.
//

WaitComplete:
if (WaitStatus != STATUS_KERNEL_APC) {
if (WaitStatus == STATUS_TIMEOUT) {
WaitStatus = STATUS_SUCCESS;
}

return WaitStatus;
}

//
// Reduce the time remaining before the time delay expires.
//

Interval = KiComputeWaitInterval(OriginalTime,
&DueTime,
&NewTime);
}

//
// Raise IRQL to DISPATCH_LEVEL and lock the dispatcher
database.
//

KiLockDispatcherDatabase(&Thread->WaitIrql);
} while (TRUE);

//
// The thread is alerted or a user APC should be delivered. Unlock
the
// dispatcher database, lower IRQL to its previous value, and
return the
// wait status.
//

KiUnlockDispatcherDatabase(Thread->WaitIrql);
return WaitStatus;
}


PLARGE_INTEGER
FASTCALL
KiComputeWaitInterval (
IN PLARGE_INTEGER OriginalTime,
IN PLARGE_INTEGER DueTime,
IN OUT PLARGE_INTEGER NewTime
)

/*++

Routine Description:

This function recomputes the wait interval after a thread has been
awakened to deliver a kernel APC.

Arguments:

OriginalTime - Supplies a pointer to the original timeout value.

DueTime - Supplies a pointer to the previous due time.

NewTime - Supplies a pointer to a variable that receives the
recomputed wait interval.

Return Value:

A pointer to the new time is returned as the function value.

--*/

{

//
// If the original wait time was absolute, then return the same
// absolute time. Otherwise, reduce the wait time remaining before
// the time delay expires.
//

if (OriginalTime->QuadPart >= 0) {
return OriginalTime;

} else {
KiQueryInterruptTime(NewTime);
NewTime->QuadPart -= DueTime->QuadPart;
return NewTime;
}
}

sdv

unread,
May 13, 2006, 2:42:02 PM5/13/06
to dev4s...@googlegroups.com
某些情况下可能会让线程永久Sleep
(书上说的)

kalos

unread,
May 14, 2006, 9:00:16 PM5/14/06
to dev4s...@googlegroups.com
牛人呀!

-----邮件原件-----
发件人: dev4s...@googlegroups.com [mailto:dev4s...@googlegroups.com] 代
表 SevenCat
发送时间: 2006年5月13日 14:22
收件人: 高性能网络编程邮件列表
主题: Re: 要在多线程里面延时1S sleep 好像不是安全的

sunway

unread,
May 15, 2006, 2:04:44 AM5/15/06
to 高性能网络编程邮件列表
就是把线程挂起来,

好人

unread,
Jun 5, 2006, 8:35:51 AM6/5/06
to 高性能网络编程邮件列表
这个贴子真火....
Reply all
Reply to author
Forward
0 new messages