<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园_我很无奈</title><subtitle type="text">明天永远是个未知数，今天的任务就是做已知变量的表达式变换。</subtitle><id>http://feed.cnblogs.com/blog/u/32337/rss</id><updated>2011-06-24T02:57:11Z</updated><author><name>鹿亮</name><uri>http://www.cnblogs.com/luliang/</uri></author><generator>feed.cnblogs.com</generator><link rel="alternate" type="text/html" href="http://www.cnblogs.com/luliang/"/><link rel="self" type="application/atom+xml" href="http://feed.cnblogs.com/blog/u/32337/rss"/><entry><id>http://www.cnblogs.com/luliang/archive/2011/06/24/2088720.html</id><title type="text">ARM程序由于字节对齐引起的问题深入分析</title><summary type="text">首先说说，什么叫对齐。如果一个数据是从偶地址开始的连续存储，那么它就是半字对齐，否则就是非半字对齐；半字对齐的特征是bit0=0,其他位为任意值。字对齐的特征是bit1=0,bit0=1,其他位为任意值。如果一个数据是以能被4 整除的地址开始的连续存储，那么它就是字对齐，否则就是非字对齐。举例说明四字节对齐： 对内存进行操作时，被访问的地址必须为4的倍数。如果分配到的地址的地址不是4的倍数时，CPU实际访问的地址还是按照字对齐的方式来操作。也就是自动屏蔽bit1和bit0. 用ADS的ARM C Complier下Optimization Level可能引起问题，其中的一个问题就是字节对齐的.</summary><published>2011-06-24T02:57:00Z</published><updated>2011-06-24T02:57:00Z</updated><author><name>鹿亮</name><uri>http://www.cnblogs.com/luliang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/luliang/archive/2011/06/24/2088720.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/luliang/archive/2011/06/24/2088720.html"/><content type="html">&lt;div&gt;&lt;span style="font-family: Arial; line-height: 24px; font-size: 12px; color: #333333; "&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;首先说说，什么叫对齐。如果一个数据是从偶地址开始的连续存储，那么它就是半字对齐，否则就是非半字对齐；半字对齐的特征是bit0=0,其他位为任意值。字对齐的特征是bit1=0,bit0=1,其他位为任意值。如果一个数据是以能被4 整除的地址开始的连续存储，那么它就是字对齐，否则就是非字对齐。举例说明四字节对齐： 对内存进行操作时，被访问的地址必须为4的倍数。如果分配到的地址的地址不是4的倍数时，CPU实际访问的地址还是按照字对齐的方式来操作。也就是自动屏蔽bit1和bit0.&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 用ADS的ARM C Complier下Optimization Level可能引起问题，其中的一个问题就是字节对齐的问题。下面讲讲问题的现象及实质。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 当时问题的现象是：程序使用一公共变量Buf创建队列，如果ADS编译优化选项采用Minium则软件工作正常；源码不变，如果采用ALL优化，则不正常，数据紊乱且无法工作。为了发现问题，我们分别用Minium和ALL编译，在反汇编条件下单步跟踪程序，观察CPU寄存器和内存变量的变化情况。发现在Minium模式下，编译器把队列内存块Uart0TxBuf分配到的地址是0x400015cc,这个地址是一个4字节对齐的地址，而在ALL模式下，编译器把Buf分配的地址是0x400015c2，这个地址是一个非4字节对齐的地址。正是由于这个非4字节对齐的地址导致了问题的发生。&lt;br /&gt;问题发生在QueueCreate(void *Buf, uint32 SizeOfBuf, uint8 (* ReadEmpty)(), uint8 (* WriteFull)())这个函数里，问题是如何发生的，&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在了解问题发生的机理前，先了解QueueCreate这个函数的工作原理。QueueCreate工作原理是，首先把buf指向的内存初始化为DataQueue格式的结构体。&amp;nbsp; DataQueue的结构体格式如下：&lt;br /&gt;typedef struct {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QUEUE_DATA_TYPE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *Out;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* 指向数据输出位置&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; */&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QUEUE_DATA_TYPE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *In;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* 指向数据输入位置&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; */&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QUEUE_DATA_TYPE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *End;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* 指向Buf的结束位置&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; */&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; uint16&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; NData;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* 队列中数据个数&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; */&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; uint16&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MaxData;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* 队列中允许存储的数据个数 */&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; uint8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (* ReadEmpty)();&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* 读空处理函数&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; */&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; uint8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (* WriteFull)();&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* 写满处理函数&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; */&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; QUEUE_DATA_TYPE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; *Buf;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* 存储数据的空间&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; */&lt;br /&gt;} DataQueue;&lt;br /&gt;从结构体可以看出，结构体字节类型在内存分配为： 4字节指针变量（*Out）、4字节指针变量（*In）、4字节指针变量（*End）、2字节变量NData、2字节变量MaxData、4字节函数指针变量ReadEmpty（）、4字节函数指针变量（WriteFull（））&lt;br /&gt;&amp;nbsp;&amp;nbsp; 观察结构体起始地址放在非对齐时会出现什么情况。&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;起始地址为0x400015c2时的由编译器分配得到的地址&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 实际操作地址&lt;br /&gt;*Out&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x400015c2~0x400015c5&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0x40015c0~0x400015c3&lt;br /&gt;*In&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x400014c6~0x400015c9&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; x400014c4~0x400015c7&lt;br /&gt;*End&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x400015ca~0x400015cd&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 0x400015c8~0x400015cb&lt;br /&gt;从表中可以看出，实际操作的地址按照4字节对齐格式得到。例如，当执行*Out进行操作时，自动屏蔽bit1和bit0,因此实际发生变化的是0x40015c0~0x400015c3，而不是0x400015c2~0x400015c5，由于实际操作地址和编译器分配地址互相覆盖，当对*In操作时，会导致*Out一起变化，对*End操作时，*In也跟着变化。正是由于非对齐的原因导致创建队列和对列操作完全错误。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 当内存起始地址为4字节对齐地址的情况时，编译器分配地址和实际地址一致，因此不存在上述问题。&lt;/p&gt;&lt;p&gt;结 论：&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 在ARM嵌入式系统中，当把一个内存区域初始化为某个结构体时，必须注意字节对齐的情况。如果该内存起始地址为非对齐地址，不仅得不到预期的结果，还可能导致一些很奇怪的让人无法理解表面问题。在C层面上不太容易观察到这些问题的实质，只有深入到汇编一层去分析程序，才可能理解这些现象的深层原因。&lt;/p&gt;&lt;/span&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/luliang/aggbug/2088720.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/luliang/archive/2011/06/24/2088720.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/luliang/archive/2011/06/24/2088700.html</id><title type="text">socket阻塞与非阻塞，同步与异步</title><summary type="text">简单点说: 阻塞就是干不完不准回来， 非组赛就是你先干，我现看看有其他事没有，完了告诉我一声 我们拿最常用的send和recv两个函数来说吧... 比如你调用send函数发送一定的Byte,在系统内部send做的工作其实只是把数据传输(Copy)到TCP/IP协议栈的输出缓冲区,它执行成功并不代表数据已经成功的发送出去了,如果TCP/IP协议栈没有足够的可用缓冲区来保存你Copy过来的数据的话...这时候就体现出阻塞和非阻塞的不同之处了:对于阻塞模式的socket send函数将不返回直到系统缓冲区有足够的空间把你要发送的数据Copy过去以后才返回,而对于非阻塞的socket来说send会立即</summary><published>2011-06-24T02:39:00Z</published><updated>2011-06-24T02:39:00Z</updated><author><name>鹿亮</name><uri>http://www.cnblogs.com/luliang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/luliang/archive/2011/06/24/2088700.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/luliang/archive/2011/06/24/2088700.html"/><content type="html">&lt;div&gt;&lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;简单点说&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;:&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;阻塞就是干不完不准回来，&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;非组赛就是你先干，我现看看有其他事没有，完了告诉我一声&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;我们拿最常用的&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;send&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;和&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;recv&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;两个函数来说吧&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;...&amp;nbsp;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;比如你调用&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;send&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;函数发送一定的&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;Byte,&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;在系统内部&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;send&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;做的工作其实只是把数据传输&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;(Copy)&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;到&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;TCP/IP&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;协议栈的输出缓冲区&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;,&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;它执行成功并不代表数据已经成功的发送出去了&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;,&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;如果&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;TCP/IP&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;协议栈没有足够的可用缓冲区来保存你&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;Copy&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;过来的数据的话&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;...&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;这时候就体现出阻塞和非阻塞的不同之处了&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;:&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;对于阻塞模式的&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;socket send&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;函数将不返回直到系统缓冲区有足够的空间把你要发送的数据&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;Copy&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;过去以后才返回&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;,&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;而对于非阻塞的&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;socket&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;来说&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;send&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;会立即返回&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;WSAEWOULDDBLOCK&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;告诉调用者说&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;:"&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;发送操作被阻塞了&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;!!!&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;你想办法处理吧&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;..."&amp;nbsp;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;对于&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;recv&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;函数&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;,&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;同样道理&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;,&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;该函数的内部工作机制其实是在等待&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;TCP/IP&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;协议栈的接收缓冲区通知它说&lt;/span&gt;&lt;span style="font-size: 10.5pt;font-family:Verdana;color:black"&gt;:&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;嗨&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;,&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;你的数据来了&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;.&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;对于阻塞模式的&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;socket&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;来说如果&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;TCP/IP&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;协议栈的接收缓冲区没有通知一个结果给它它就一直不返回&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;:&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;耗费着系统资源&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;....&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;对于非阻塞模式的&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;socket&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;该函数会马上返回&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;,&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;然后告诉你&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;:WSAEWOULDDBLOCK---"&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;现在没有数据&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;,&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;回头在来看看&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;"&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;在进行网络编程时，我们常常见到同步、异步、阻塞和非阻塞四种调用方式。这些方式彼此概念并不好理解。下面是我对这些术语的理解。&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;同步&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;所谓同步，就是在发出一个功能调用时，在没有得到结果之前，该调用就不返回。按照这个定义，其实绝大多数函数都是同步调用（例如&lt;/span&gt;&lt;span&gt;&lt;span style="font-size:10.5pt;font-family: Verdana;color:black"&gt;sin, isdigit&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;等）。但是一般而言，我们在说同步、异步的时候，特指那些需要其他部件协作或者需要一定时间完成的任务。最常见的例子就是&lt;/span&gt;&lt;span&gt;&lt;span style="font-size:10.5pt;font-family: Verdana;color:black"&gt; SendMessage&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;。该函数发送一个消息给某个窗口，在对方处理完消息之前，这个函数不返回。当对方处理完毕以后，该函数才把消息处理函数所返回的&lt;/span&gt;&lt;span&gt;&lt;span style="font-size:10.5pt;font-family: Verdana;color:black"&gt; LRESULT&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;值返回给调用者。&lt;/span&gt;&lt;span style="font-size: 10.5pt;font-family:Verdana;color:black"&gt;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;异步&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;异步的概念和同步相对。当一个异步过程调用发出后，调用者不能立刻得到结果。实际处理这个调用的部件在完成后，通过状态、通知和回调来通知调用者。以&lt;/span&gt;&lt;span&gt;&lt;span style="font-size:10.5pt;font-family: Verdana;color:black"&gt; CAsycSocket&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;类为例（注意，&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;CSocket&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;从&lt;/span&gt;&lt;span&gt;&lt;span style="font-size:10.5pt;font-family: Verdana;color:black"&gt;CAsyncSocket&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;派生，但是起功能已经由异步转化为同步），当一个客户端通过调用&lt;/span&gt;&lt;span&gt;&lt;span style="font-size:10.5pt;font-family: Verdana;color:black"&gt; Connect&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;函数发出一个连接请求后，调用者线程立刻可以朝下运行。当连接真正建立起来以后，&lt;/span&gt;&lt;span&gt;&lt;span style="font-size:10.5pt;font-family: Verdana;color:black"&gt;socket&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;底层会发送一个消息通知该对象。这里提到执行&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;部件和调用者通过三种途径返回结果：状态、通知和回调。可以使用哪一种依赖于执行部件的实现，除非执行部件提供多种选择，否则不受调用者控制。如果执行部&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;件用状态来通知，那么调用者就需要每隔一定时间检查一次，效率就很低（有些初学多线程编程的人，总喜欢用一个循环去检查某个变量的值，这其实是一种很严重&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;的错误）。如果是使用通知的方式，效率则很高，因为执行部件几乎不需要做额外的操作。至于回调函数，其实和通知没太多区别。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;阻塞&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;阻塞调用是指调用结果返回之前，当前线程会被挂起。函数只有在得到结果之后才会返回。有人也许会把阻塞调用和同步调用等同起来，实际上他是不同的。对于同&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;步调用来说，很多时候当前线程还是激活的，只是从逻辑上当前函数没有返回而已。例如，我们在&lt;/span&gt;&lt;span&gt;&lt;span style="font-size:10.5pt;font-family: Verdana;color:black"&gt;CSocket&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;中调用&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;Receive&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;函数，如果缓冲区中没有数&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;据，这个函数就会一直等待，直到有数据才返回。而此时，当前线程还会继续处理各种各样的消息。如果主窗口和调用函数在同一个线程中，除非你在特殊的界面操&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;作函数中调用，其实主界面还是应该可以刷新。&lt;/span&gt;&lt;span&gt;&lt;span style="font-size:10.5pt;font-family: Verdana;color:black"&gt;socket&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;接收数据的另外一个函数&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;recv&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;则是一个阻塞调用的例子。当&lt;/span&gt;&lt;span&gt;&lt;span style="font-size:10.5pt;font-family: Verdana;color:black"&gt;socket&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;工作在阻塞模式的时候，&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;如果没有数据的情况下调用该函数，则当前线程就会被挂起，直到有数据为止。&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;非阻塞&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;非阻塞和阻塞的概念相对应，指在不能立刻得到结果之前，该函数不会阻塞当前线程，而会立刻返回。&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;对象的阻塞模式和阻塞函数调用&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&lt;br /&gt; &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性，但是并不是一一对应的。阻塞对象上可以有非阻塞的调用方式，我们可以通过一定的&lt;/span&gt;&lt;span&gt;&lt;span style="font-size:10.5pt;font-family: Verdana;color:black"&gt;API&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;去轮询状&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;态，在适当的时候调用阻塞函数，就可以避免阻塞。而对于非阻塞对象，调用特殊的函数也可以进入阻塞调用。函数&lt;/span&gt;&lt;span&gt;&lt;span style="font-size:10.5pt;font-family: Verdana;color:black"&gt;select&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;就是这样的一个例子。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;阻塞通信&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;--------------------------------------------------------------------------------&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;通过重叠通信和计算在许多系统能提高性能。由一个智能通信控制器自动地执行通信的系统是真实的。轻－重线索是取得这种重叠的一种机制。导致好性能的&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;一个可选的机制是使用非阻塞通信。一个阻塞发送开始调用初始化这个发送操作，但不完成它。在这个消息被从这个发送缓存拷出以前，这个发送开始调用将返回。&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;需要一个独立的&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;&amp;#8220;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;发送完成&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&amp;#8221;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;调用完成这个通信，例如，检验从发送缓存拷出的数据。用适当的硬件，在发送被初始化后和它完成以前，来自发送者存储的数据转换&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;可以和在发送者完成的计算同时进行。类似地，一个非阻塞&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&amp;#8220;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;接收开始调用&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;&amp;#8221;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;初始化这个接收操作&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;, &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;但不完成它。在一个消息被存入这个接收缓存以前，这个调用将返回。须要一个独立的&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&amp;#8220;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;接收完成&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;&amp;#8221;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;调用完成这个接收操作，并检验被接收到这个接收缓存的数据。&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;用适当的硬件，在接收操作初始化后和它完成以前，到接收者存储的数据转换可以和计算同时进行。非阻塞接收的使用虽着信息较早地在接收缓存位置被提供，也可&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;以避免系统缓存和存储器到存储器拷贝。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;非阻塞发送开始调用能使用与阻塞发送一样的四种模式&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;: &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;标准&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;, &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;缓存&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;, &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;同步和准备好模式。这些具有同样的意义。无论一个匹配接收是否已登入，能开始除&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&amp;#8220;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;准备好&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;&amp;#8221;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;以外的所有模式的发送；只要一个匹配接收已登入，就能开始一个非&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;阻塞&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;&amp;#8220;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;准备好&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&amp;#8221;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;发送。在所有情况下，发送开始调用是局部的：无论其它进程的状态如何，它立刻返回。如果这个调用使得一些系统资源用完，那么它将失败并返回&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;一个错误代码。高质量的&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;MPI&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;实现应保证这种情况只在&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&amp;#8220;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;病态&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;&amp;#8221;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;时发生。即，一个&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;MPI&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;实现将能支持大数量挂起非阻塞操作。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;当数据已被从发送缓存拷出时，这个发送完成调用返回。它可以带有附加的意义，这取决于发送模式。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;如果发送模式是&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;&amp;#8220;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;同步的&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&amp;#8221;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;，那么只有一个匹配接收已开始这个发送才能完成。即，一个接收已被登入，并已和这个发送匹配。这时，这个发送完成调用是非&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;局部的。注意，在接收完成调用发生以前，如果一个同步、非阻塞发送和一个非阻塞接收匹配&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;, &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;它可以完成。&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;(&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;发送者一&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&amp;#8220;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;知道&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;&amp;#8221;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;转换将结束，它就能完成，但在接收者&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&amp;#8220;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;知道&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;&amp;#8221;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;转换将结束以前&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;)&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;如果发送模式是&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;&amp;#8220;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;缓存&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;&amp;#8221;&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;，并没有挂起接收，那么消息必须被缓存。这时，发送完成调用是局部的，而且无论一个匹配接收的状态如何，它必须成功。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;如果发送模式是标准的，同时这个消息被缓存，那么在一个匹配接收发生以前，发送结束调用可以返回。另一方面，发送完成直到一个匹配接收发生才可以完成，并且这个消息已被拷到接收缓存。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;非阻塞发送能被用阻塞接收匹配，反过来也可以。&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;给用户的建议&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;. &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;一个发送操作的完成&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;, &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;对于标准模式可以被延迟&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;, &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;对于同部模式必须延迟&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;, &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;直到一个匹配接收登入。这两种情况下非阻塞发送的使用允许发送者提前于接收者进行，以便在两进程的速度方面，计算更容忍波动。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;缓存和准备好模式中的非阻塞发送有一个更有限的影响。一可能一个非阻塞发送将返回，而一个阻塞发送将在数据被从发送者存储拷出后返回。只要在数据拷贝能和计算同时的情况下，非阻塞发送的使用有优点。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&lt;span style="font-size:10.5pt;color:black"&gt;消息发送模式隐含着由发送者初始化通信。当发送者初始化通信&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;(&lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;数据被直接移到接收缓存&lt;/span&gt;&lt;span style="font-size:10.5pt; font-family:Verdana;color:black"&gt;, &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;并不要求排队一个挂起发送请求&lt;/span&gt;&lt;span style="font-size:10.5pt;font-family:Verdana;color:black"&gt;) &lt;/span&gt;&lt;span style="font-size:10.5pt;color:black"&gt;时，如果一个接收已登入，这个通信一般将有较低的额外负担。但是，只在匹配发送已发生后，一个接收操作能完成。当非阻塞接收等待发送时，没有阻塞接收，它&lt;/span&gt; &lt;span style="font-size:10.5pt;color:black"&gt;的使用允许得到较低的通信额外负担。&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;    &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/div&gt;&lt;img src="http://www.cnblogs.com/luliang/aggbug/2088700.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;&lt;a href="http://www.cnblogs.com/luliang/archive/2011/06/24/2088700.html" target="_blank"&gt;本文链接&lt;/a&gt;&lt;/p&gt;</content></entry><entry><id>http://www.cnblogs.com/luliang/archive/2008/08/21/1272746.html</id><title type="text">extern用法详解(转) </title><summary type="text">1 基本解释extern可以置于变量或者函数前，以标示变量或者函数的定义在别的文件中，提示编译器遇到此变量和函数时在其他模块中寻找其定义。另外，extern也可用来进行链接指定。2 问题：extern 变量在一个源文件里定义了一个数组：char a[6];在另外一个文件里用下列语句进行了声明：extern char *a；请问，这样可以吗？ 答案与分析：1)、不可以，程...</summary><published>2008-08-21T01:13:00Z</published><updated>2008-08-21T01:13:00Z</updated><author><name>鹿亮</name><uri>http://www.cnblogs.com/luliang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/luliang/archive/2008/08/21/1272746.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/luliang/archive/2008/08/21/1272746.html"/><content type="text">1 基本解释extern可以置于变量或者函数前，以标示变量或者函数的定义在别的文件中，提示编译器遇到此变量和函数时在其他模块中寻找其定义。另外，extern也可用来进行链接指定。2 问题：extern 变量在一个源文件里定义了一个数组：char a[6];在另外一个文件里用下列语句进行了声明：extern char *a；请问，这样可以吗？ 答案与分析：1)、不可以，程...</content></entry><entry><id>http://www.cnblogs.com/luliang/archive/2008/07/05/1236696.html</id><title type="text">转载typedef用法</title><summary type="text">一.基本概念剖析 int* (*a[5])(int, char*); //＃1void (*b[10]) (void (*)()); //＃2double(*)() (*pa)[9]; //＃3 1．C语言中函数声明和数组声明。函数声明一般是这样： int fun(int, double);对应函数指针（pointer to function）的声明是这样： int (*pf)(int, do...</summary><published>2008-07-05T12:22:00Z</published><updated>2008-07-05T12:22:00Z</updated><author><name>鹿亮</name><uri>http://www.cnblogs.com/luliang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/luliang/archive/2008/07/05/1236696.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/luliang/archive/2008/07/05/1236696.html"/><content type="text">一.基本概念剖析 int* (*a[5])(int, char*); //＃1void (*b[10]) (void (*)()); //＃2double(*)() (*pa)[9]; //＃3 1．C语言中函数声明和数组声明。函数声明一般是这样： int fun(int, double);对应函数指针（pointer to function）的声明是这样： int (*pf)(int, do...</content></entry><entry><id>http://www.cnblogs.com/luliang/archive/2008/07/05/1236283.html</id><title type="text">转载</title><summary type="text">如何学好C++，用好类库很重要TheEdge推荐[2007-6-24]出处：ACE开发者作者：不详如果你有一定的C基础可能学起来比较容易些,但是学习C++的过程中又要尽量避免去使用一些C中的思想;平时还要多看一些高手写的代码,遇到问题多多思考,怎样才能把问题抽象化,以使自己头脑中有类的概念;最后别忘了经常上机自己调调程序,这是谁也代替不了的. C++类库介绍 再次体现了C++保持核心语言的效率同...</summary><published>2008-07-05T06:56:00Z</published><updated>2008-07-05T06:56:00Z</updated><author><name>鹿亮</name><uri>http://www.cnblogs.com/luliang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/luliang/archive/2008/07/05/1236283.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/luliang/archive/2008/07/05/1236283.html"/><content type="text">如何学好C++，用好类库很重要TheEdge推荐[2007-6-24]出处：ACE开发者作者：不详如果你有一定的C基础可能学起来比较容易些,但是学习C++的过程中又要尽量避免去使用一些C中的思想;平时还要多看一些高手写的代码,遇到问题多多思考,怎样才能把问题抽象化,以使自己头脑中有类的概念;最后别忘了经常上机自己调调程序,这是谁也代替不了的. C++类库介绍 再次体现了C++保持核心语言的效率同...</content></entry><entry><id>http://www.cnblogs.com/luliang/archive/2008/07/02/1233802.html</id><title type="text">Web导出excel的问题</title><summary type="text">有时候需要web业上导出数据文件，我们可以用html的形式导出，就是构造一个table，然后让类似与下面的一段代码处理private void SaveAsExcel(string html) { System.IO.StringWriter writer = new System.IO.StringWriter(); writer.Write(html); System.Web.UI.HtmlT...</summary><published>2008-07-02T03:04:00Z</published><updated>2008-07-02T03:04:00Z</updated><author><name>鹿亮</name><uri>http://www.cnblogs.com/luliang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/luliang/archive/2008/07/02/1233802.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/luliang/archive/2008/07/02/1233802.html"/><content type="text">有时候需要web业上导出数据文件，我们可以用html的形式导出，就是构造一个table，然后让类似与下面的一段代码处理private void SaveAsExcel(string html) { System.IO.StringWriter writer = new System.IO.StringWriter(); writer.Write(html); System.Web.UI.HtmlT...</content></entry><entry><id>http://www.cnblogs.com/luliang/archive/2008/05/13/1195729.html</id><title type="text">不错的资料站</title><summary type="text">http://ajax.cnrui.cn/ 主要是一些ajax方面的东西</summary><published>2008-05-13T12:35:00Z</published><updated>2008-05-13T12:35:00Z</updated><author><name>鹿亮</name><uri>http://www.cnblogs.com/luliang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/luliang/archive/2008/05/13/1195729.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/luliang/archive/2008/05/13/1195729.html"/><content type="text">http://ajax.cnrui.cn/ 主要是一些ajax方面的东西</content></entry><entry><id>http://www.cnblogs.com/luliang/archive/2008/05/13/1195728.html</id><title type="text">window for javascript</title><summary type="text">熟练window对象的open、close、alert、confirm、prompt、setTimeout、clearTimeout、setInterval、clearInterval、moveBy、resizeBy、scrollBy方法的使用 掌握window对象的moveTo、resizeTo、scrollTo、print方法的使用 熟练掌握window对象的status、location、n...</summary><published>2008-05-13T12:32:00Z</published><updated>2008-05-13T12:32:00Z</updated><author><name>鹿亮</name><uri>http://www.cnblogs.com/luliang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/luliang/archive/2008/05/13/1195728.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/luliang/archive/2008/05/13/1195728.html"/><content type="text">熟练window对象的open、close、alert、confirm、prompt、setTimeout、clearTimeout、setInterval、clearInterval、moveBy、resizeBy、scrollBy方法的使用 掌握window对象的moveTo、resizeTo、scrollTo、print方法的使用 熟练掌握window对象的status、location、n...</content></entry><entry><id>http://www.cnblogs.com/luliang/archive/2008/05/13/1194782.html</id><title type="text">MSA 企业设计</title><summary type="text">转一篇文章http://www.microsoft.com/china/technet/itsolutions/techguide/msa/vmhtm25.mspx</summary><published>2008-05-13T02:52:00Z</published><updated>2008-05-13T02:52:00Z</updated><author><name>鹿亮</name><uri>http://www.cnblogs.com/luliang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/luliang/archive/2008/05/13/1194782.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/luliang/archive/2008/05/13/1194782.html"/><content type="text">转一篇文章http://www.microsoft.com/china/technet/itsolutions/techguide/msa/vmhtm25.mspx</content></entry><entry><id>http://www.cnblogs.com/luliang/archive/2008/04/18/1159447.html</id><title type="text">绑定数据</title><summary type="text">灵活的运用数据绑定操作 绑定到简单属性:&lt;%#UserName%&gt; 绑定到集合:&lt;asp:ListBox id="ListBox1" datasource='&lt;%# myArray%&gt;' runat="server"&gt; 绑定到表达式:&lt;%#(class1.property1.ToString() + "," + class1.property2.ToStr...</summary><published>2008-04-18T02:32:00Z</published><updated>2008-04-18T02:32:00Z</updated><author><name>鹿亮</name><uri>http://www.cnblogs.com/luliang/</uri></author><link rel="alternate" href="http://www.cnblogs.com/luliang/archive/2008/04/18/1159447.html"/><link rel="alternate" type="text/html" href="http://www.cnblogs.com/luliang/archive/2008/04/18/1159447.html"/><content type="text">灵活的运用数据绑定操作 绑定到简单属性:&lt;%#UserName%&gt; 绑定到集合:&lt;asp:ListBox id="ListBox1" datasource='&lt;%# myArray%&gt;' runat="server"&gt; 绑定到表达式:&lt;%#(class1.property1.ToString() + "," + class1.property2.ToStr...</content></entry></feed>
