用SetTimer回调的问题,回调函数的执行在哪个线程里?

时间:2022-09-06 14:04:38
如果在主线程里调用了SetTimer,那么回调函数的执行是在主线程里?
如果在子线程里调用了SetTimer,那么回调函数的执行是在子线程里?

31 个解决方案

#1


回调函数是全局的和线程没关系.

#2


但是总属于某个进程/线程来执行的吧,如果回调访问程序里的资源,是否要做互斥呢

#3


lz的假设完全正确

#4


时间器只跟窗口有关。

#5


timer应该和线程无关,是系统调用的

#6


"时间器只跟窗口有关"
如果::SetTimer的窗口句柄设为NULL呢

"timer应该和线程无关,是系统调用的"
系统回调程序里的代码时,到底是运行在程序所运行的进程中,还是有一个系统进程?

如果是在程序所运行的进程中,那么在进程中的哪个线程,是SetTimer调用者所在的线程吗?
如果是在调用者所在的线程,那么若调用者所在的线程退出了,那么回调还能发生吗?会出错吗?

#7


加点分,欢迎高手解答

#8


关注

#9


虽然是系统调用的,但是当前进程会阻塞到OnTimer返回为止

为了能够异步调用,最好是在回调中建立一个线程,然后立即返回

#10


大致分析一下Winmain或者WinProc之类,就可以得出一个比较直接的结论

#11


摘自MSDN,SetTimer函数
An application can process WM_TIMER messages by including a WM_TIMER case statement in the window procedure or by specifying a TimerProc callback function when creating the timer. When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc instead of processing WM_TIMER. 
由上文知,回调函数是在window procedure中调用的,而且它也是对消息WM_TIMER的处理时才调用的,所以它是在窗口线程中执行的,如果回调函数执行时间很长,会使消息线程阻掉,造成窗口死掉。

#12


系统回调程序里的代码时,到底是运行在程序所运行的进程中,还是有一个系统进程?

timer其实是一个内核对象,也就是说可以跨进程的.但是如果引用它的进程关闭了,timer也会被删除.
回调函数可以说是独立于进程里面的线程的,ontimer就不是很清楚了,要看mfc的实现.

#13


说错了,应该是由settimer所在线程调用的

#14


向窗口注册了的Timer是由主窗口处理函数所在线程执行
没注册窗口句柄的Timer是由系统线程执行.

#15


可以在OnTimer里Sleep()做实验

#16


内核对象timer的回调是由settimer所在线程调用的

#17


归纳一下大家的意见,把问题挖掘到底

如果是注册窗口的,则在窗口消息处理线程中执行,此时可能是在主线程中,也可以在用户界面子线程中,取决于该窗口消息处理所在的线程;
(问题:假设我创建的是用户界面子线程,然后在主线程中调用SetTimer将回调注册到该子线程中,那么调用SetTimer所运行的线程和回调函数所运行的就不是一个线程喽?)

如果没有注册窗口的,则是在调用SetTimer所在的线程中运行,此时与回调函数所在的线程是同一个线程。
(这里有人说回调是在系统线程中进行,到底什么是系统线程?)

#18


mark

#19


学习

#20


测试了一下,有如下现象:
1.在子线程中以无窗口SetTimer,回调函数仍然在子线程中被调用。
2.如果子线程没有消息循环,则回调函数始终不会被调用。
3.如果子线程只GetMessage不DispatchMessage,回调函数也不会被调用。
4.但在回调函数的堆栈中没有发现DispatchMessage入口。
结论是:
回调的执行与SetTimer是同样的线程,可以近似认为是由DispatchMessage这句话调用它(但不是直接调用)

#21


Timer事件是在消息队列的处理函数DispatchMessage中被调用的,消息队列是跟线程相关的,每个线程都拥有一个独立的消息队列,在哪个线程创建的Timer就会在哪个线程激发Timer事件,所以楼主的猜想是正确的。具体可参阅《Windows核心编程》

#22


学到点东西.我之前想当然的说,没想到线程消息循环的问题.

#23


学习一下

#24


谢谢大家,结帐

#25


谁创建,谁释放

#26


最后问一下:
若开辟了一个界面线程A,然后在主线程B上调用了A的方法,A方法中调用了SetTimer,窗口句柄使用了界面线程A的句柄,则回调是在界面线程A上运行吧;
若调用SetTimer时窗口句柄设为NULL,那么回调是在主线程B上执行的吧?

#27


"窗口句柄使用了界面线程A的句柄,则回调是在界面线程A上运行吧"
这个经测试通过
"然后在主线程B上调用了A的方法,A方法中调用了SetTimer"
A方法如果是在主线程B上调用,那么也就相当于在主线程上调用SetTimer了,所以这个实际上和我们原来讨论的是一样的。

#28


该回复被版主删除

#29


嗯,我自己编写了一个测试程序,证实了上面的观点,即:
若SetTimer传入的窗口句柄为NULL,则回调在调用SetTimer的线程上运行;
若传入的窗口句柄不为NULL,则回调在拥有窗口句柄的线程上运行,此时,调用SetTimer的线程和拥有窗口句柄的线程可以是同一个线程,也可以是不同线程

#30


“  回复人:lxinjing1234() () 信誉:100  2006-12-30 10:27:13
 
  http://www.nud8.com/mlm/?mid=ownmoney  ”

不要在这里做广告!!

#31



"然后在主线程B上调用了A的方法,A方法中调用了SetTimer"
A方法如果是在主线程B上调用,那么也就相当于在主线程上调用SetTimer了,所以这个实际上和我们原来讨论的是一样的。

但是,这要看调用SetTimer时传入的窗口句柄是否为NULL,是NULL,则哪个线程调用SetTimer,就在哪个线程回调,无论回调代码和SetTimer代码在哪里;如果句柄不为NULL,则一定是在拥有该窗口句柄的线程里回调,也无论回调代码和SetTimer代码在哪里。

这个是经我测验得到的结论

#1


回调函数是全局的和线程没关系.

#2


但是总属于某个进程/线程来执行的吧,如果回调访问程序里的资源,是否要做互斥呢

#3


lz的假设完全正确

#4


时间器只跟窗口有关。

#5


timer应该和线程无关,是系统调用的

#6


"时间器只跟窗口有关"
如果::SetTimer的窗口句柄设为NULL呢

"timer应该和线程无关,是系统调用的"
系统回调程序里的代码时,到底是运行在程序所运行的进程中,还是有一个系统进程?

如果是在程序所运行的进程中,那么在进程中的哪个线程,是SetTimer调用者所在的线程吗?
如果是在调用者所在的线程,那么若调用者所在的线程退出了,那么回调还能发生吗?会出错吗?

#7


加点分,欢迎高手解答

#8


关注

#9


虽然是系统调用的,但是当前进程会阻塞到OnTimer返回为止

为了能够异步调用,最好是在回调中建立一个线程,然后立即返回

#10


大致分析一下Winmain或者WinProc之类,就可以得出一个比较直接的结论

#11


摘自MSDN,SetTimer函数
An application can process WM_TIMER messages by including a WM_TIMER case statement in the window procedure or by specifying a TimerProc callback function when creating the timer. When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc instead of processing WM_TIMER. 
由上文知,回调函数是在window procedure中调用的,而且它也是对消息WM_TIMER的处理时才调用的,所以它是在窗口线程中执行的,如果回调函数执行时间很长,会使消息线程阻掉,造成窗口死掉。

#12


系统回调程序里的代码时,到底是运行在程序所运行的进程中,还是有一个系统进程?

timer其实是一个内核对象,也就是说可以跨进程的.但是如果引用它的进程关闭了,timer也会被删除.
回调函数可以说是独立于进程里面的线程的,ontimer就不是很清楚了,要看mfc的实现.

#13


说错了,应该是由settimer所在线程调用的

#14


向窗口注册了的Timer是由主窗口处理函数所在线程执行
没注册窗口句柄的Timer是由系统线程执行.

#15


可以在OnTimer里Sleep()做实验

#16


内核对象timer的回调是由settimer所在线程调用的

#17


归纳一下大家的意见,把问题挖掘到底

如果是注册窗口的,则在窗口消息处理线程中执行,此时可能是在主线程中,也可以在用户界面子线程中,取决于该窗口消息处理所在的线程;
(问题:假设我创建的是用户界面子线程,然后在主线程中调用SetTimer将回调注册到该子线程中,那么调用SetTimer所运行的线程和回调函数所运行的就不是一个线程喽?)

如果没有注册窗口的,则是在调用SetTimer所在的线程中运行,此时与回调函数所在的线程是同一个线程。
(这里有人说回调是在系统线程中进行,到底什么是系统线程?)

#18


mark

#19


学习

#20


测试了一下,有如下现象:
1.在子线程中以无窗口SetTimer,回调函数仍然在子线程中被调用。
2.如果子线程没有消息循环,则回调函数始终不会被调用。
3.如果子线程只GetMessage不DispatchMessage,回调函数也不会被调用。
4.但在回调函数的堆栈中没有发现DispatchMessage入口。
结论是:
回调的执行与SetTimer是同样的线程,可以近似认为是由DispatchMessage这句话调用它(但不是直接调用)

#21


Timer事件是在消息队列的处理函数DispatchMessage中被调用的,消息队列是跟线程相关的,每个线程都拥有一个独立的消息队列,在哪个线程创建的Timer就会在哪个线程激发Timer事件,所以楼主的猜想是正确的。具体可参阅《Windows核心编程》

#22


学到点东西.我之前想当然的说,没想到线程消息循环的问题.

#23


学习一下

#24


谢谢大家,结帐

#25


谁创建,谁释放

#26


最后问一下:
若开辟了一个界面线程A,然后在主线程B上调用了A的方法,A方法中调用了SetTimer,窗口句柄使用了界面线程A的句柄,则回调是在界面线程A上运行吧;
若调用SetTimer时窗口句柄设为NULL,那么回调是在主线程B上执行的吧?

#27


"窗口句柄使用了界面线程A的句柄,则回调是在界面线程A上运行吧"
这个经测试通过
"然后在主线程B上调用了A的方法,A方法中调用了SetTimer"
A方法如果是在主线程B上调用,那么也就相当于在主线程上调用SetTimer了,所以这个实际上和我们原来讨论的是一样的。

#28


该回复被版主删除

#29


嗯,我自己编写了一个测试程序,证实了上面的观点,即:
若SetTimer传入的窗口句柄为NULL,则回调在调用SetTimer的线程上运行;
若传入的窗口句柄不为NULL,则回调在拥有窗口句柄的线程上运行,此时,调用SetTimer的线程和拥有窗口句柄的线程可以是同一个线程,也可以是不同线程

#30


“  回复人:lxinjing1234() () 信誉:100  2006-12-30 10:27:13
 
  http://www.nud8.com/mlm/?mid=ownmoney  ”

不要在这里做广告!!

#31



"然后在主线程B上调用了A的方法,A方法中调用了SetTimer"
A方法如果是在主线程B上调用,那么也就相当于在主线程上调用SetTimer了,所以这个实际上和我们原来讨论的是一样的。

但是,这要看调用SetTimer时传入的窗口句柄是否为NULL,是NULL,则哪个线程调用SetTimer,就在哪个线程回调,无论回调代码和SetTimer代码在哪里;如果句柄不为NULL,则一定是在拥有该窗口句柄的线程里回调,也无论回调代码和SetTimer代码在哪里。

这个是经我测验得到的结论