函数的可重入和C++中Sendmessage 和 PostMessage 的区别

1、什么是函数的可重入性?
重入一般可以理解为一个函数在同时多次调用,列如操作系统在进程调度过程中,或者单片机,处理器等的中断的时候发生冲入的现象


一般可重入的函数必须满足下列3个条件:
(1)可以在执行的过程中被打断
(2)被打断之后,该函数一次调用执行完以前,可以再次被调用
(3)再次调用执行完以后,被打断的上次调用可以继续恢复执行,并正确执行


.可重入与线程安全
可重入的定义源于单线程环境。在单线程环境下,一段代码在执行中可能被硬件中断,并转而调用中断服务程序(ISR)。在本次调用中断处理函数之前,有可能中断处理函数已经在执行。因此,任何中断处理函数都应该是可重入的。
线程安全的概念则源自于多线程环境。可见,他们的起源是不一样的。那么,他们没有什么必然关系呢。可总结如下:
(1)一个线程安全的函数不一定是可重入的;
(2)一个可重入的函数缺也不一定是线程安全的!


下面这个swap函数是不可重入的:
[cpp] view plain copy print?
int t;  
   
void swap(int *x, int *y)  
{  
    t = *x;  
    *x = *y;  
   
    // hardware interrupt might invoke isr() here!  
    *y = t;  
}  
   
void isr()  
{  
    int x = 1, y = 2;  
    swap(&x, &y);  
}  
既然它不可重入则它一定不是线程安全的。
可以把t改成线程局部变量,使得该函数变成线程安全。然而,这样修改的话,swap函数依然是不可重入的。例如一个线程已经在执行swap函数,这个时候在同样的语境下收到硬件中断,isr()函数会被调用,进而调用swap,swap的不可重入问题就暴露出来了


我们做一定修改,在swap函数里,在交换前,对此时刻的t全局变量做一个本地的缓存,在交换结束的时候,始终使用该缓存。这样的话,swap函数在退出的时候,全局变量的之跟进入的时候是一样的。这样,就可以保证该函数是线程可重入的。代码如下:
[cpp] view plain copy print?
int t;  
   
void swap(int *x, int *y)  
{  
    int s;  
   
  <span style="color:#FF0000;">  s = t; // save global variable</span>  
    t = *x;  
    *x = *y;  
   
    // hardware interrupt might invoke isr() here!  
    *y = t;  
<span style="color:#FF0000;">    t = s; // restore global variable</span>  
}  
   
void isr()  
{  
    int x = 1, y = 2;  
    swap(&x, &y);  
}  
2、C++中Sendmessage 和 PostMessage 的区别?


概述
Send有发送的意思,而Post具有投寄的意思。 联想一下现实生活中我们写信(很久很久以前。。。。)来记就很简单了: 
Send:  相当于邮寄员,他会将快件亲手交给收件人,并且需要收件人签字,他才闪人。而在消息机制中,就是说,系统(邮寄员)会将收到的消息(邮局分发)直接发送到某个窗口的窗口过程(收件人),并且需要该窗口作出处理(收件人签字)才返回。 这东东就是SendMessage。
Post:  相当于邮局、邮筒等等,我们写好信好,会将信交给邮局,或投寄到邮筒里,而什么时候发送,发送到哪里都由邮局来处理,我们投寄信件的时候,是不会等候这封信件到达收件人手里,然后才回家的。
 在消息机制中,就是说,系统(我们)将收到的消息(信件)投寄到应用程序的消息循环(相当于邮筒)中,然后就闪人,具体啥时候处理这条消息(啥时候发送邮件),那就得看“办事效率”了。


介绍
SendMessage
将指定的消息发送到一个窗口或多个窗口。SendMessage为这个指定的消息调用窗口处理程序,直到窗口处理完这个程序后才会返回。和SendMessage函数相比,PostMessage函数发送一个消息到线程消息对列中,并立即返回。
函数原型:LRESULT SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);
参数:
hWnd:其窗口程序将接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。
Msg:指定被发送的消息。
wParam:指定附加的消息指定信息。
IParam:指定附加的消息指定信息。
返回值:返回值指定消息处理的结果,依赖于所发送的消息。
备注:需要用HWND_BROADCAST通信的应用程序应当使用函数RegisterWindowMessage来为应用程序间的通信取得一个唯一的消息。
如果指定的窗口是由调用线程创建的,则窗口程序立即作为子程序调用。如果指定的窗口是由不同线程创建的,则系统切换到该线程并调用恰当的窗口程序。线程间的消息只有在线程执行消息检索代码时才被处理。发送线程被阻塞直到接收线程处理完消息为止。
PostMessage
该函数将一个消息放入(寄送)到与指定窗口创建的线程相联系消息队列里,不等待线程处理消息就返回。消息队列里的消息通过调用GetMessage和PeekMessage取得。
函数原型:B00L PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
参数:
    hWnd:其窗口程序接收消息的窗口的句柄。可取有特定含义的两个值:
    HWND.BROADCAST:消息被寄送到系统的所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口。消息不被寄送到子窗口。
    NULL:此函数的操作和调用参数dwThread设置为当前线程的标识符PostThreadMessage函数一样。
    Msg:指定被寄送的消息。
    wParam:指定附加的消息特定的信息。
    IParam:指定附加的消息特定的信息。
返回值:如果函数调用成功,返回非零值:如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。


分析
1, PostMessage只把消息放入队列,不管其他程序是否处理都返回,然后继续执行,这是个异步消息投放函数。而SendMessage必须等待其他程序处理消息完了之后才返回,继续执行,这是个同步消息投放函数。
2, 如果在同一个线程内,PostMessage发送消息时,消息要先放入线程的消息队列,然后通过消息循环Dispatch到目标窗口。SendMessage发送消息时,系统直接调用目标窗口的消息处理程序,并将结果返回,SendMessage在同一线程中发送消息并不入线程消息队列。
3,PostMessage的返回值表示PostMessage函数执行是否正确;而SendMessage的返回值表示其他程序处理消息后的返回值。这点大家应该都明白。
4,如果在不同线程内。最好用PostThreadMessage代替PostMessage,他工作的很好,SendMessage发送消息到目标窗口所属的线程的消息队列,然后发送消息的线程等待(事实上,他应该还在做一些监测工作,比如监视QS_SENDMESSAGE标志),直到目标窗口处理完并且结果返回,发送消息的线程才继续运行。


总结
区别很明显,SendMessage的消息是不进队列的,而PostMessage的需要排队。值得说明的是:虽然一个要进队,一个不进队,但是最终处理消息的地方都一样:都是系统调用窗口过程进行处理(收件人作出反应)。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值