﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-蓝莓日记Cass#-随笔分类-Windows程序设计</title><link>http://www.cppblog.com/Cass/category/16517.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 12 Oct 2011 00:37:57 GMT</lastBuildDate><pubDate>Wed, 12 Oct 2011 00:37:57 GMT</pubDate><ttl>60</ttl><item><title>内存池基本</title><link>http://www.cppblog.com/Cass/archive/2011/10/11/158012.html</link><dc:creator>Yu_</dc:creator><author>Yu_</author><pubDate>Tue, 11 Oct 2011 00:45:00 GMT</pubDate><guid>http://www.cppblog.com/Cass/archive/2011/10/11/158012.html</guid><wfw:comment>http://www.cppblog.com/Cass/comments/158012.html</wfw:comment><comments>http://www.cppblog.com/Cass/archive/2011/10/11/158012.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Cass/comments/commentRss/158012.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Cass/services/trackbacks/158012.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1、为什么使用内存池？<br>      通常我们习惯直接使用new、malloc等API申请分配内存，这样做的缺点在于：由于所申请内存块的大小不定，当频繁使用时会造成大量的内存碎片并进而降低性能。<br>&nbsp;&nbsp;<a href='http://www.cppblog.com/Cass/archive/2011/10/11/158012.html'>阅读全文</a><img src ="http://www.cppblog.com/Cass/aggbug/158012.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Cass/" target="_blank">Yu_</a> 2011-10-11 08:45 <a href="http://www.cppblog.com/Cass/archive/2011/10/11/158012.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>线程池的使用（转）</title><link>http://www.cppblog.com/Cass/archive/2011/10/10/157926.html</link><dc:creator>Yu_</dc:creator><author>Yu_</author><pubDate>Mon, 10 Oct 2011 01:25:00 GMT</pubDate><guid>http://www.cppblog.com/Cass/archive/2011/10/10/157926.html</guid><wfw:comment>http://www.cppblog.com/Cass/comments/157926.html</wfw:comment><comments>http://www.cppblog.com/Cass/archive/2011/10/10/157926.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Cass/comments/commentRss/157926.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Cass/services/trackbacks/157926.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 为什么要使用线程池：<br>创建多线程应用程序是非常困难的。需要会面临两个大问题。<br>一个是要对线程的创建和撤消进行管理，另一个是要对线程对资源的访问实施同步　。　<br>&nbsp;&nbsp;<a href='http://www.cppblog.com/Cass/archive/2011/10/10/157926.html'>阅读全文</a><img src ="http://www.cppblog.com/Cass/aggbug/157926.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Cass/" target="_blank">Yu_</a> 2011-10-10 09:25 <a href="http://www.cppblog.com/Cass/archive/2011/10/10/157926.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>线程与内核对象的同步</title><link>http://www.cppblog.com/Cass/archive/2011/10/08/157727.html</link><dc:creator>Yu_</dc:creator><author>Yu_</author><pubDate>Fri, 07 Oct 2011 16:10:00 GMT</pubDate><guid>http://www.cppblog.com/Cass/archive/2011/10/08/157727.html</guid><wfw:comment>http://www.cppblog.com/Cass/comments/157727.html</wfw:comment><comments>http://www.cppblog.com/Cass/archive/2011/10/08/157727.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Cass/comments/commentRss/157727.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Cass/services/trackbacks/157727.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 若干种内核对象，包括进程，线程和作业。可以将所有这些内核对象用于同步目的。对于线程同步来说，这些内核对象中的每种对象都可以说是处于已通知或未通知的状态之中。<br><br>例如：：当进程正在运行的时候，进程内核对象处于未通知状态，当进程终止运行的时候，它就变为已通知状态。进程内核对象中是个布尔值，当对象创建时，该值被初始化为FALSE（未通知状态）。当进程终止运行时，操作系统自动将对应的对象布尔值改为TRUE，表示该对象已经得到通知。当线程终止运行时，操作系统会自动将线程对象的状态改为已通知状态。因此，可以将相同的方法用于应用程序，以确定线程是否不再运行。<br>&nbsp;&nbsp;<a href='http://www.cppblog.com/Cass/archive/2011/10/08/157727.html'>阅读全文</a><img src ="http://www.cppblog.com/Cass/aggbug/157727.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Cass/" target="_blank">Yu_</a> 2011-10-08 00:10 <a href="http://www.cppblog.com/Cass/archive/2011/10/08/157727.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>线程通信与同步</title><link>http://www.cppblog.com/Cass/archive/2011/10/07/157725.html</link><dc:creator>Yu_</dc:creator><author>Yu_</author><pubDate>Fri, 07 Oct 2011 15:58:00 GMT</pubDate><guid>http://www.cppblog.com/Cass/archive/2011/10/07/157725.html</guid><wfw:comment>http://www.cppblog.com/Cass/comments/157725.html</wfw:comment><comments>http://www.cppblog.com/Cass/archive/2011/10/07/157725.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Cass/comments/commentRss/157725.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Cass/services/trackbacks/157725.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 线程需要在下面两种情况下互相进行通信：<br>• 当有多个线程访问共享资源而不使资源被破坏时。<br>• 当一个线程需要将某个任务已经完成的情况通知另外一个或多个线程时。<br>&nbsp;&nbsp;<a href='http://www.cppblog.com/Cass/archive/2011/10/07/157725.html'>阅读全文</a><img src ="http://www.cppblog.com/Cass/aggbug/157725.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Cass/" target="_blank">Yu_</a> 2011-10-07 23:58 <a href="http://www.cppblog.com/Cass/archive/2011/10/07/157725.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>线程</title><link>http://www.cppblog.com/Cass/archive/2011/10/07/157718.html</link><dc:creator>Yu_</dc:creator><author>Yu_</author><pubDate>Fri, 07 Oct 2011 15:10:00 GMT</pubDate><guid>http://www.cppblog.com/Cass/archive/2011/10/07/157718.html</guid><wfw:comment>http://www.cppblog.com/Cass/comments/157718.html</wfw:comment><comments>http://www.cppblog.com/Cass/archive/2011/10/07/157718.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Cass/comments/commentRss/157718.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Cass/services/trackbacks/157718.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1、线程的组成<br>（1）、一个是线程的内核对象，操作系统用它管理线程。内核对象还是系统用来存放线程统计信息的地方。<br>（2）、一个线程堆栈，用于维护线程执行时所需的所有函数参数和局部变量。<br>&nbsp;&nbsp;<a href='http://www.cppblog.com/Cass/archive/2011/10/07/157718.html'>阅读全文</a><img src ="http://www.cppblog.com/Cass/aggbug/157718.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Cass/" target="_blank">Yu_</a> 2011-10-07 23:10 <a href="http://www.cppblog.com/Cass/archive/2011/10/07/157718.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>进程间通信与同步</title><link>http://www.cppblog.com/Cass/archive/2011/10/07/157698.html</link><dc:creator>Yu_</dc:creator><author>Yu_</author><pubDate>Fri, 07 Oct 2011 07:44:00 GMT</pubDate><guid>http://www.cppblog.com/Cass/archive/2011/10/07/157698.html</guid><wfw:comment>http://www.cppblog.com/Cass/comments/157698.html</wfw:comment><comments>http://www.cppblog.com/Cass/archive/2011/10/07/157698.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Cass/comments/commentRss/157698.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Cass/services/trackbacks/157698.html</trackback:ping><description><![CDATA[<div>讨论三个问题：<br />1、进程间如何通信呢，如何来相互传递信息呢？<br />（1）、<span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">低级通信：</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">只能传递状态和整数值（控制信息）</span> </div>
<div style="text-align: left; margin-top: 6.72pt; text-indent: -0.31in; unicode-bidi: embed; direction: ltr; margin-bottom: 0pt; margin-left: 0.81in; vertical-align: baseline; language: zh-CN; punctuation-wrap: hanging"><span style="color: #000000; font-size: 12pt">&#8211;</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">信号量（</span><span style="font-family: 'Times New Roman'; color: #000000; font-size: 12pt; font-weight: bold; language: en-US; text-combine: letters">semaphore</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; font-weight: bold; language: zh-CN; text-combine: letters">）</span></div>
<div style="text-align: left; margin-top: 6.72pt; text-indent: -0.31in; unicode-bidi: embed; direction: ltr; margin-bottom: 0pt; margin-left: 0.81in; vertical-align: baseline; language: zh-CN; punctuation-wrap: hanging"><span style="color: #000000; font-size: 12pt">&#8211;</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">信号（</span><span style="font-family: 'Times New Roman'; color: #000000; font-size: 12pt; font-weight: bold; language: en-US; text-combine: letters">signal</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; font-weight: bold; language: zh-CN; text-combine: letters">）</span></div>
<div style="text-align: left; margin-top: 7.68pt; text-indent: -0.38in; unicode-bidi: embed; direction: ltr; margin-bottom: 0pt; margin-left: 0.38in; vertical-align: baseline; language: zh-CN; punctuation-wrap: hanging"><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">（2）、高级通信：</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">能够传送任意数量的数据</span></div>
<div style="text-align: left; margin-top: 6.72pt; text-indent: -0.31in; unicode-bidi: embed; direction: ltr; margin-bottom: 0pt; margin-left: 0.81in; vertical-align: baseline; language: zh-CN; punctuation-wrap: hanging"><span style="color: #000000; font-size: 12pt">&#8211;</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">共享内存（</span><span style="font-family: 'Times New Roman'; color: #000000; font-size: 12pt; font-weight: bold; language: en-US; text-combine: letters">shared memory</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; font-weight: bold; language: zh-CN; text-combine: letters">）</span></div>
<div style="text-align: left; margin-top: 6.72pt; text-indent: -0.31in; unicode-bidi: embed; direction: ltr; margin-bottom: 0pt; margin-left: 0.81in; vertical-align: baseline; language: zh-CN; punctuation-wrap: hanging"><span style="color: #000000; font-size: 12pt">&#8211;</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">消息传递（</span><span style="font-family: 'Times New Roman'; color: #000000; font-size: 12pt; font-weight: bold; language: en-US; text-combine: letters">message passing</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; font-weight: bold; language: zh-CN; text-combine: letters">）</span></div>
<div style="text-align: left; margin-top: 6.72pt; text-indent: -0.31in; unicode-bidi: embed; direction: ltr; margin-bottom: 0pt; margin-left: 0.81in; vertical-align: baseline; language: zh-CN; punctuation-wrap: hanging"><span style="color: #000000; font-size: 12pt">&#8211;</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">管道（</span><span style="font-family: 'Times New Roman'; color: #000000; font-size: 12pt; font-weight: bold; language: en-US; text-combine: letters">pipe</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; font-weight: bold; language: zh-CN; text-combine: letters">）<br /></span></div>
<div><strong>剪贴板：<br /><br /></strong>基本机制是：系统预留的一块全局共享内存，可用于被各进程暂时存储数据。写入进程首先创建一个全局内存块，并将数据写到该内存块；接受数据的进程通过剪贴板机制获取此内存块的句柄，并完成对该内存块数据的读取。<br /><br /><strong>管道包括三种:<br /></strong>管道(Pipe)实际是用于进程间通信的一段共享内存，创建管道的进程称为管道服务器，连接到一个管道的进程为管道客户机。一个进程在向管道写入数据后，另一进程就可以从管道的另一端将其读取出来。匿名管道(Anonymous Pipes)是在父进程和子进程间单向传输数据的一种未命名的管道，只能在本地计算机中使用，而不可用于网络间的通信。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1)<span style="color: red">普通管道</span>PIPE, 通常有种限制,一是半双工,只能<span style="color: red">单向传输</span>;&nbsp; 二是只能在<a href="http://baike.baidu.com/view/527045.htm" target="_blank"><font color="#136ec2"><span style="color: red">父子</span></font></a><span style="color: red">或者兄弟进程间使用</span>.&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2)<span style="color: red">流管道</span>s_pipe: 去除了第一种限制,可以<span style="color: red">双向传输</span>.&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3)<a href="http://baike.baidu.com/view/1197718.htm" target="_blank"><font color="#136ec2"><span style="color: red">命</span><span style="color: red">名</span><span style="color: red">管道</span></font></a>:name_pipe, 去除了第二种限制,<span style="color: red">可以在许多并不相关的进程之间进行通讯.<br /></span><br /><strong>邮件槽：<br /></strong>　　邮件槽(Mailslots)提供进程间<span style="color: red">单向通信能力</span>，任何进程都能建立邮件槽成为邮件槽服务器。其它进程，称为邮件槽客户，可以通过邮件槽的名字给邮件槽服务器进程发送消息。进来的消息一直放在邮件槽中，直到服务器进程读取它为止。一个进程既可以是邮件槽服务器也可以是邮件槽客户，因此可<span style="color: red">建立多个邮件槽实现进程间的双向通信。</span><br />　　通过邮件槽可以给本地计算机上的邮件槽、其它计算机上的邮件槽或指定网络区域中所有计算机上有同样名字的邮件槽发送消息。广播通信的消息长度不能超过400字节，非广播消息的长度则受邮件槽服务器指定的最大消息长度的限制。<br />　　邮件槽与命名管道相似，不过它传输数据是<span style="color: red">通过不可靠的数据报(如TCP/IP协议中的UDP包)完成的</span>，一旦网络发生错误则无法保证消息正确地接收，而命名管道传输数据则是建立在可靠连接基础上的。不过邮件槽有简化的编程接口和给指定网络区域内的所有计算机广播消息的能力，所以邮件槽不失为应用程序发送和接收消息的另一种选择。<br /><br /><span style="widows: 2; text-transform: none; text-indent: 0px; border-collapse: separate; font: medium Simsun; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(0,0,0); word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"><span style="line-height: 24px; font-family: arial, 宋体, sans-serif; font-size: 14px" class="Apple-style-span"></span></span><span style="widows: 2; text-transform: none; text-indent: 0px; border-collapse: separate; font: medium Simsun; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(0,0,0); word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"><span style="line-height: 24px; font-family: arial, 宋体, sans-serif; font-size: 14px" class="Apple-style-span"></span></span>优缺点：<br />邮槽最大的一个缺点便是只允许从客户机到服务器，建立一种不可靠的单向数据通信。<br />而另一方面，邮槽最大的一个优点在于，它们使客户机应用能够非常容易地将广播消息发送给一个或多个服务器应用。<br /><br /><strong>共享内存：<br /></strong>
<p>存在于内核级别的一种资源，共享内存指在多处理器的<a href="http://baike.baidu.com/view/1130583.htm" target="_blank"><font color="#136ec2">计算机系统</font></a>中，可以被不同中央处理器（CPU）访问的<span style="color: red">大容量内存</span>。由于多个CPU需要快速访问存储器，这样就要对存储器进行缓存（Cache）。任何一个缓存的数据被更新后，由于其他处理器也可能要存取，共享内存就需要立即更新，否则不同的处理器可能用到不同的数据。共享内存 (shared memory)是 Unix下的多进程之间的通信方法 ,这种方法通常用于一个程序的多进程间通信，实际上多个程序间也可以通过共享内存来传递信息。<br /></p><br /><br />2、当两个或者多个进程访问共享资源时，如何确保他们不会相互妨碍-----进程互斥问题。<br /><br />原因：<span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters; mso-ascii-font-family: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-bidi-font-family: +mn-cs; mso-font-kerning: 12.0pt">进程宏观上并发执行，</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters; mso-ascii-font-family: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-bidi-font-family: +mn-cs; mso-font-kerning: 12.0pt">依靠时钟中断来实现微观上轮流执行。当两个或者多个进程对同一个共享内存访问，结果不能预测。<span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters; mso-ascii-font-family: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-bidi-font-family: +mn-cs; mso-font-kerning: 12.0pt">在同一时刻，只允许一个进程访问该共享数据，</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters; mso-ascii-font-family: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-bidi-font-family: +mn-cs; mso-font-kerning: 12.0pt">即如果当前已有一个进程正在使用该数据，那么</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters; mso-ascii-font-family: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-bidi-font-family: +mn-cs; mso-font-kerning: 12.0pt">其他进程暂时不能访问。这就是</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; font-weight: bold; language: zh-CN; text-combine: letters; mso-ascii-font-family: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-bidi-font-family: +mn-cs; mso-font-kerning: 12.0pt">互斥</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters; mso-ascii-font-family: 'Times New Roman'; mso-fareast-font-family: 宋体; mso-bidi-font-family: +mn-cs; mso-font-kerning: 12.0pt">的概念。<br />实现互斥访问的四个条件：&nbsp; </div>
<div style="text-align: left; margin-top: 16.8pt; text-indent: -0.5in; unicode-bidi: embed; direction: ltr; margin-bottom: 0pt; margin-left: 0.5in; vertical-align: baseline; language: zh-CN; punctuation-wrap: simple"><span style="color: #000000; font-size: 12pt">（1）、</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">任何两个进程都不能同时进入临界区；</span></div>
<div style="text-align: left; margin-top: 16.8pt; text-indent: -0.5in; unicode-bidi: embed; direction: ltr; margin-bottom: 0pt; margin-left: 0.5in; vertical-align: baseline; language: zh-CN; punctuation-wrap: simple"><span style="color: #000000; font-size: 12pt">（2）、</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">不能事先假定</span><span style="font-family: 'Times New Roman'; color: #000000; font-size: 12pt; font-weight: bold; language: en-US; text-combine: letters">CPU</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">的个数和运行速度；</span></div>
<div style="text-align: left; margin-top: 16.8pt; text-indent: -0.5in; unicode-bidi: embed; direction: ltr; margin-bottom: 0pt; margin-left: 0.5in; vertical-align: baseline; language: zh-CN; punctuation-wrap: simple"><span style="color: #000000; font-size: 12pt">&nbsp;(3)、</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">当一个进程运行在它的临界区外面时，</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">不能妨碍其他的进程进入临界区；</span></div>
<div style="text-align: left; margin-top: 16.8pt; text-indent: -0.5in; unicode-bidi: embed; direction: ltr; margin-bottom: 0pt; margin-left: 0.5in; vertical-align: baseline; language: zh-CN; punctuation-wrap: simple"><span style="color: #000000; font-size: 12pt">（4）、</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">任何一个进程进入临界区的要求应该在</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">有限时间内得到满</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; font-weight: bold; language: zh-CN; text-combine: letters">足。<br /><br /></span></div></span></span>
<div><strong>（解决办法）<br /></strong>（1）、用标志位加锁。 
<p style="margin: 0cm 0cm 10pt"><span style="font-size: 12pt">lock</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">的初始值为</span><span style="font-size: 12pt">0</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">，当一个进程想进入临界区时，</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">先查看</span><span style="font-size: 12pt">lock</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">的值，若为</span><span style="font-size: 12pt">1</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">，说明已有进程在临界区</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">内，只好循环等待。等它变成了</span><span style="font-size: 12pt">0</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">，才可进入。</span><span style="font-family: '微软雅黑','sans-serif'"><br /></span><br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/cass/进程同步1.jpg" /><br /><span style="font-size: 12pt">缺点是：lock也是一个共享资源，当进程竞争lock时，可能会出现问题。</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">加锁标志位法的缺点在于可能</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">出现针对共享变量</span><span style="font-size: 12pt"> lock </span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">的竞争</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">状态。例如，当进程</span><span style="font-size: 12pt"> 0 </span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">执行完</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">循环判断语句后，被时钟中断</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">打断，从而可能使多个进程同</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">时进入临界区。</span><br /><span style="font-size: 12pt">是一种不安全的做法、</span><br />（2）、强制轮流法</p>
<p style="margin: 0cm 0cm 10pt"><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">基本思想：每个进程严格地按照轮流的顺序来</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">进入临界区。</span></p>
<p style="margin: 0cm 0cm 10pt"><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">优点：保证在任何时刻最多只有一个进程在临界区</span><span style="font-family: '微软雅黑','sans-serif'"><br /></span><span style="font-family: '微软雅黑','sans-serif'; font-size: 12pt">缺点：违反了互斥访问四条件中的第三个条件，<span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">当一个进程运行在它的临界区外面时，</span><span style="font-family: 宋体; color: #000000; font-size: 12pt; language: zh-CN; text-combine: letters">不能妨碍其他的进程进入临界区</span><br /><br /><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/cass/进程同步2.jpg" width="567" height="244" /><br /><br />（3）、<span style="font-family: 'Times New Roman'; color: #333333; font-size: 12pt; font-weight: normal; language: en-US; text-combine: letters; mso-ascii-font-family: 'Times New Roman'; mso-fareast-font-family: 黑体; mso-bidi-font-family: +mn-cs; mso-font-kerning: 12.0pt; mso-color-index: 1">Peterson方法。</span></p>
<p style="margin: 0cm 0cm 10pt"><span style="font-family: '微软雅黑','sans-serif'">当一个进程想进入临界区时，先调用</span>enter_region<span style="font-family: '微软雅黑','sans-serif'">函数，判断是否能安全进入，不能的话等待；当它</span><span style="font-family: '微软雅黑','sans-serif'">从临界区退出后，需调用</span>leave_region<span style="font-family: '微软雅黑','sans-serif'">函数，允许其</span><span style="font-family: '微软雅黑','sans-serif'">它进程进入临界区。两个函数的参数均为进程号。<img style="width: 553px; height: 283px" border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/cass/进程同步5.jpg" width="553" height="283" /><br /></span></p>
<p style="margin: 0cm 0cm 10pt"></p>
<p style="margin: 0cm 0cm 10pt"><img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/cass/线程同步4.jpg" /><br /><br />小结：<br /></p>
<p style="margin: 0cm 0cm 10pt"><span style="font-family: '微软雅黑','sans-serif'">当一个进程想要进</span><span style="font-family: '微软雅黑','sans-serif'">入它的临界区时，首先检查一下是否允许它进入，</span><span style="font-family: '微软雅黑','sans-serif'">若允许，就直接进入了；若不允许，就在那里循环</span><span style="font-family: '微软雅黑','sans-serif'">地等待，一直等到允许它进入。<br /></span></p>
<p style="margin: 0cm 0cm 10pt"></p>
<p style="margin: 0cm 0cm 10pt"><span style="font-family: '微软雅黑','sans-serif'">缺点：</span><br />&nbsp;&nbsp;&nbsp;&nbsp;1<span style="font-family: '微软雅黑','sans-serif'">）浪费</span>CPU<span style="font-family: '微软雅黑','sans-serif'">时间；<br /></span>&nbsp;&nbsp;&nbsp;&nbsp;2<span style="font-family: '微软雅黑','sans-serif'">）可能导致预料之外</span><span style="font-family: '微软雅黑','sans-serif'">的结果（如：一个低优先级进程位于临界区中，这时有一个高优先级的进程也试图进入临界区）<br /></span></span><br />3、当进程间存在某种依存关系时，如何来调整他们运行的先后次序-----进程同步问题。<br /><span class="headline-content">用P，V原语操作实现同步（略）</span><br />另外：上述的问题也适合线程吗？？&nbsp; </p></div><img src ="http://www.cppblog.com/Cass/aggbug/157698.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Cass/" target="_blank">Yu_</a> 2011-10-07 15:44 <a href="http://www.cppblog.com/Cass/archive/2011/10/07/157698.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>进程管理</title><link>http://www.cppblog.com/Cass/archive/2011/10/07/157686.html</link><dc:creator>Yu_</dc:creator><author>Yu_</author><pubDate>Fri, 07 Oct 2011 03:19:00 GMT</pubDate><guid>http://www.cppblog.com/Cass/archive/2011/10/07/157686.html</guid><wfw:comment>http://www.cppblog.com/Cass/comments/157686.html</wfw:comment><comments>http://www.cppblog.com/Cass/archive/2011/10/07/157686.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Cass/comments/commentRss/157686.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Cass/services/trackbacks/157686.html</trackback:ping><description><![CDATA[<div>1、什么是进程？<br />：：一般将进程定义成一个正在运行的程序的一个实例。进程由两部分组成：<br />&#9312;、<span style="color: red">一个内核对象</span>，操作系统用它来管理进程。内核对象也是系统保存进程统计信息的地方。<br />&#9313;、<span style="color: red">一个地址空间</span>，其中包含所有执行体（executable）或DLL模块的代码和数据。此外，它还包含动态内存分配，比如线程堆栈和堆的分配。<br /><span style="color: red">进程与线程的关系：</span><br />&#9312;、一个进程创建的时候，系统会自动创建它的第一个线程，这称为主线程（primary thread）。<br />&#9313;、进程要做任何事情，都必须让一个线程在它的上下文中运行。如果没有线程要执行进程地址空间包含的代码，进程就失去了继续存在的理由。所以，系统会自动销毁进程及其地址空间。<br />&#9314;、一个进程可以有多个线程，所有线程都在进程的地址空间中&#8220;同时&#8221;执行代码。为此，每个线程都有它自己的一组CPU寄存器和它自己的堆栈。对于所有要运行的线程，操作系统会轮流为每个线程调度一些CPU时间。它会采取round-robin（轮询或轮流）方式，为每个线程都分配时间片，从而营造出所有线程都在&#8220;并发&#8221;运行的假象。<br /><br />2、系统如何创建一个进程内核对象来管理每个进程。<br /><span style="widows: 2; text-transform: none; text-indent: 0px; border-collapse: separate; font: medium Simsun; white-space: normal; orphans: 2; letter-spacing: normal; color: rgb(0,0,0); word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class="Apple-style-span"><span style="text-align: left; line-height: 23px; font-family: simsun; font-size: 14px" class="Apple-style-span">当一个进程被初始化时，系统要为它分配一个句柄表(空的，也就是用来管理进程的内核对象)。该句柄表只用于内核对象（而不用于用户对象和gdi对象)。句柄表是一个数据结构的数组，每个结构都包含一个指向内核对象的指针，一个<span class="Apple-converted-space">&nbsp;</span>访问屏蔽(DWORD)和一个标志(DWORD)。<br />：：：当进程中的线程调用创建内核对象的函数（比如<span class="Apple-converted-space">&nbsp;</span>CreatFileMapping)时，内核就为该对象分配一个内存块并对它初始化。<strong>同时对进程的句柄表进行扫描，找出一个空项，填充内核对象数据结构的内存地址到该顶的指针成员，设置访问屏蔽和标志。<br />：：：</strong><span class="Apple-converted-space">&nbsp;</span>用于创建内核对象的所有函数均返回与进程相关的句柄。该句柄实际上是放入进程的句柄表中的索引<span class="Apple-converted-space">&nbsp;</span>（由此可知，句柄是与进程相关的，不能由其他进程直接成功地使用)。但这只适用部分系统，句柄的含义可能随时变更。<span class="Apple-converted-space">&nbsp;</span>应用程序在运行时有可能泄漏内核对象，但是当进程终止时系统将能确保所有内容均被正确地清除。这个情况也适用于所有对象，资源和内存块，也就是说当进程终止运行时，系统将保证进程不会留<span class="Apple-converted-space">&nbsp;</span>下任何对象。</span></span><br /><br />3、如何利用与一个进程关联的内核对象来操纵该进程。<br /><br />4、进程的各种不同的属性（或特性），以及用于查询和更改这些属性的几个函数。<br />实例句柄、前一个实例句柄、进程的命令行、进程的环境变量、进程当前所在的驱动器和目录、还有版本问题等<br /><br />5、如何利用一些函数在系统中创建或生成额外的进程。<br />我们用CreateProcess函数来创建一个进程，参考MSDN。当一个线程调用CreateProcess时，系统会做如下工作：<br />（1）、系统将<span style="color: red">创建一个进程内核对象</span>，其初始使用计数为<span style="color: red">1</span>。进程内核对象不是进程本身，而是操作系统用来管理这个进程的一个小型数据结构（<span style="color: red">该内核对象是用来管理新进程的）。<br /></span>（2）、系统<span style="color: red">为新进程创建一个虚拟地址空间</span>，并将执行体文件（和所有必要的DLL）的代码及数据加载到进程的地址空间。<br />（3）、系统<span style="color: red">为新进程的主线程创建一个线程内核对象</span>（使用计数为1）。和进程内核对象一样，线程内核对象也是一个小型数据结构，操作系统用它来管理这个线程。这个主线程一开始就会执行由链接器设为应用程序入口的C/C++运行时启动例程，并最终调用你的WinMain，wWinMain，main或wmain函数。<br />（4）、如果系统成功创建了新进程和主线程，CreateProcess将返回TRUE。<br /><span style="color: red">创建子进程后：</span><br />创建一个进程内核对象时，系统会为此对象分配一个独一无二的标识符，系统中没有别的进程内核对象会有相同的ID编号<br /><br /><br />6、如何终止线程。<br />关闭到一个进程或线程的句柄，不会强迫系统杀死此进程或线程。关闭句柄只是告诉系统你对进程或线程的统计数据<br />不再感兴趣了。进程或线程会继续执行，直至自行终止。（<span style="color: red">计数，重点是计数）<br />进程可以通过以下4种方式终止：<br />（1）、主线程的入口函数返回（强烈推荐的方式）。<br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;让主线程的入口函数返回，可以保证发生以下几件事情：<br /></span><span style="color: #000000">􀂾 该线程创建的任何C++对象都将由这些对象的析构函数正确销毁。<br /></span><span style="color: #000000">􀂾 操作系统将正确释放线程堆栈使用的内存。<br /></span><span style="color: #000000">􀂾 系统将进程的退出代码（在进程内核对象中维护）设为你的入口函数的返回值。<br /></span><span style="color: #000000">􀂾 系统递减进程内核对象的使用计数。</span><span style="color: #000000"><br /></span><span style="color: #ff0000">（2）、进程中的一个线程调用ExitProcess函数（要避免这个方式）<br /></span><span style="color: #000000">进程会在该进程中的一个线程调用ExitProcess函数时终止：<br /></span><span style="color: #000000">VOID ExitProcess(UINT fuExitCode);<br />一旦你的应用程序的主线程从它的入口函数返回，那么不管当前在进程中是否正在运行其他线程，都会调用ExitProcess来终止进程。不过，如果在入口函数中调用ExitThread，而不是调用ExitProcess或者简单地返回，应用程序的主线程将停止执行，但只要进程中还有其他线程正在运行，进程就不会终止。<br /></span><span style="color: #000000"><br /></span><span style="color: #ff0000">（3）、另一个进程中的线程调用TerminateProcess函数（要避免这个方式）<br /></span><span style="color: #000000">调用TerminateProcess也可以终止一个进程，但是进程无法将它在内存中的任何信息转储到磁盘上。</span><span style="color: #ff0000"><br /></span><span style="color: #ff0000">（4）、进程中的所有线程都&#8220;自然死亡&#8221;（这是很难发生的）</span><span style="color: #ff0000"><br /></span></div><img src ="http://www.cppblog.com/Cass/aggbug/157686.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Cass/" target="_blank">Yu_</a> 2011-10-07 11:19 <a href="http://www.cppblog.com/Cass/archive/2011/10/07/157686.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内核对象</title><link>http://www.cppblog.com/Cass/archive/2011/10/06/157645.html</link><dc:creator>Yu_</dc:creator><author>Yu_</author><pubDate>Thu, 06 Oct 2011 09:27:00 GMT</pubDate><guid>http://www.cppblog.com/Cass/archive/2011/10/06/157645.html</guid><wfw:comment>http://www.cppblog.com/Cass/comments/157645.html</wfw:comment><comments>http://www.cppblog.com/Cass/archive/2011/10/06/157645.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Cass/comments/commentRss/157645.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Cass/services/trackbacks/157645.html</trackback:ping><description><![CDATA[<div>1、什么是内核对象？<br />内核对象的数据结构只能由内核访问。<br />他们有：令牌（access token）对象、事件对象、文件对象、文件映射对象、I/O完成端口对象、作业对象、mailslot对象、mutex对象、pipe对象、进程对象、semaphore对象、线程对象、waitable timer对象以及thread pool worker factory对象等等。大多数成员都是不同的对象类型特有的。<br />2、生命周期。<br />取决与其计数：<br /><span style="color: red">内核对象的所有者是内核，而非进程。</span>换言之，如果你的进程调用一个函数来创建了一个内核对象，然后进程终止运行，则内核对象并不一定会销毁。大多数情况下，这个内核对象是会销毁的，但假如另一个进程正在使用你的进程创建的内核对象，那么在其他进程停止使用它之前，它是不会销毁的。总之，内核对象的生命期可能长于创建它的那个进程。<br />内核知道当前有多少个进程正在使用一个特定的内核对象，因为每个对象都包含一个使用计数（usage count）。<br /><br />使用计数是所有内核对象类型都有的一个数据成员。初次创建一个对象的时候，其使用计数被设为<span style="color: red">1</span>。另一个进程获得对现有内核对象的访问后，使用计数就会递增。进程终止运行后，内核将自动递减此进程仍然打开的所有内核对象的使用计数。一个对象的使用计数变成0，内核就会销毁该对象。这样一来，可以保证系统中不存在没有被任何进程引用的内核对象。<br /><br />3、管理内核对象<br />一个进程在初始化时，系统将为它分配一个句柄表。一个进程的句柄表，它只是一个由数据结构组成的数组。每个结构<br />都包含指向一个内核对象的指针、一个访问掩码（access mask）和一些标志。<br />（1）、创建一个内核对象<br />一个进程首次初始化的时候，其句柄表为空。当进程内的一个线程调用一个会创建内核对象的函数时，内核将为这个对象分配并初始化一个内存块。然后，内核扫描进程的句柄表，查找一个空白的记录项（empty entry）。指针成员会被设置成内核对象的数据结构的内部内存地址，访问掩码将被设置成拥有完全访问权限，标志也会设置。<br /><br />如果创建调用失败，那么返回的句柄值通常为0（NULL）。之所以失败，可能是由于系统内存不足，或者遇到了一个安全问题。遗憾的是，有几个函数在调用失败时会返回句柄值&#8211;1。所以要看清楚再判断。<br />（2）、关闭内存对象<br />无论以什么方式创建内核对象，都要调用CloseHandle向系统指出你已经结束使用对象：<br />BOOL CloseHandle(HANDLE hobject);<br />结束时需要注意：：；<br /><font color="#000000" face="Verdana">&nbsp;&nbsp;&nbsp;&#9312;、在内部，该函数首先检查主调进程的句柄表，验证&#8220;传给函数的句柄值&#8221;标识的是&#8220;进程确实有权访问的一个对象&#8221;。如果句柄是有效的，系统就将获得内核对象的数据结构的地址，并在结构中递减&#8220;使用计数&#8221;成员。如果使用计数变成0，内核对象将被销毁，并从内存中删除。<br />&nbsp;&nbsp;&nbsp;&#9313;、一旦调用CloseHandle，你的进程就不能访问那个内核对象。<br /></font>&nbsp;&nbsp;&nbsp;&#9314;、如果对象的使用计数没有递减至0，它就不会被销毁。它表明另外<span style="color: red">还有一个或多个</span>进程在使用该对象。当其他进程全部停止使用这个对象后（通过调用CloseHandle），对象就会被销毁。<br />&nbsp;&nbsp;&nbsp;&#9315;、在创建一个内核对象时，我们会将它的句柄保存到一个变量中。将此变量作为参数调用了CloseHandle函数后，还应同时将这个变量设为NULL。<br />&nbsp;&nbsp;&nbsp;&#9316;、当进程终止运行，操作系统会确保此进程所使用的所有资源都被释放！对于内核对象，操作系统执行的是以下操作：进程终止时，系统自动扫描该进程的句柄表。如果这个表中有任何有效的记录项（即进程终止前没有关闭的对象），操作系统会为你关闭这些对象句柄。任何这些对象的使用计数递减至0，内核就会销毁对象。<br /><br />（3）、进程共享内核对象、<br />很多地方需要用到进程共享内核对象。例如<br />&#9312;、利用文件映射对象，可以在同一台机器上运行的两个不同进程<span style="color: red">之间共</span><span style="color: red">享数</span><span style="color: red">据块。&nbsp;</span>&nbsp; <br />&#9313;、借助mailslots（信箱）和named pipes（匿名管道），在网络中的不同计算机上运行的进程可以相互发送数据块。<br />&#9314;、mutexes（互斥对象）、semaphores（信标对象）和事件允许不同进程中的线程同步执行。例如，一个应用程序可能需要在完成某个任务之后，向另一个应用程序发出通知。<br /><br /><strong>三种不同的机制来允许进程共享内核对象：</strong><strong style="color: red">使用对象句柄继承；为对象命名；以及复制对象句柄。</strong><strong><br /></strong>&nbsp;&nbsp;1 使用对象句柄继承<br />设置可继承标志为1。对象句柄的继承只会在生成子进程的时候发生。<br />程序初始化时会为父进程创建一个进程句柄表，使用对象句柄继承，系统会为子进程创建一个新的、空白的进程句柄表&#8212;&#8212;就像它为任何一个新进程所做的那样。系统会遍历父进程的句柄表，对它的每一个记录项进行检查。凡是包含一个有效的&#8220;可继承的句柄&#8221;的项，都会被完整地拷贝到子进程的句柄表。在子进程的句柄表中，拷贝项的位置与它在父进程句柄表中的位置是完全一样的。这是非常重要的一个设计，因为它意味着：在父进程和子进程中，对一个内核对象进行标识的句柄值是完全一样的。内核对象的使用计数将递增。<br />2、改变句柄的标志<br />&nbsp;父进程创建了一个内核对象，得到了一个可继承的句柄，然后生成了两个子进程。但是，父进程只希望其中的一个子进程继承内核对象句柄。调用SetHandleInformation函数来改变内核对象句柄的继承标志。函数具体参考MSDN。&nbsp;<br />3、为对象命名<br />不能创建相同名字的对象，类型不同也不行。进程间共享：<br />进程A 有某个命名"JeffMutex" 对象 hMutexProcessA,那么进程B 创建一个同样"JeffMutex" 对象时。，<br />系统首先会查看是否存在一个名为&#8220;JeffMutex&#8221;的内核对象。由于确实存在这样的一个对象，所以内核接着检查对象的类型。由于试图创建一个mutex，而名为&#8220;JeffMutex&#8221;的对象也是一个mutex，所以系统接着执行一次安全检查，验证调用者是否拥有对象的完全访问权限。如果答案是肯定的，系统就会在Process B的句柄表中查找一个空白记录项，并将其初始化为指向现有的内核对象。如果对象的类型不匹配，或调用者被拒绝访问，CreateMutex就会失败（返回NULL）。<br />这样就实现了进程共享对象。但问题是进程B不知道自己创建的是新对象，还是用久对象。<br />（4）、复制对象句柄<br />为了跨越进程边界来共享内核对象，最后一个技术是使用DuplicateHandle函数。<br />这个函数获得一个进程的句柄表中的一个记录项，然后在另一个进程的句柄表中创建这个记录项的一个拷贝。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /></div><img src ="http://www.cppblog.com/Cass/aggbug/157645.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Cass/" target="_blank">Yu_</a> 2011-10-06 17:27 <a href="http://www.cppblog.com/Cass/archive/2011/10/06/157645.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>组件与接口的概念</title><link>http://www.cppblog.com/Cass/archive/2011/09/21/156462.html</link><dc:creator>Yu_</dc:creator><author>Yu_</author><pubDate>Wed, 21 Sep 2011 11:54:00 GMT</pubDate><guid>http://www.cppblog.com/Cass/archive/2011/09/21/156462.html</guid><wfw:comment>http://www.cppblog.com/Cass/comments/156462.html</wfw:comment><comments>http://www.cppblog.com/Cass/archive/2011/09/21/156462.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Cass/comments/commentRss/156462.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Cass/services/trackbacks/156462.html</trackback:ping><description><![CDATA[<p style="text-indent: -36pt; margin: 0cm 0cm 10pt 36pt"><span>1、<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: '微软雅黑','sans-serif'">组件：组件是将应用程序分割成多个独立部分，维护时用新组件替代旧组件。而传统的应用程序是将程序分割成文件、模块和类，将他们编译并链接成一大块。</span></p>
<p style="margin: 0cm 0cm 10pt"><span style="font-family: '微软雅黑','sans-serif'">组件特点：</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt"><span>&#9312;<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span><span style="font-family: '微软雅黑','sans-serif'">、可修改，可替换，满足用户的需求</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt"><span>&#9313;<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span><span style="font-family: '微软雅黑','sans-serif'">、有组件库可以快速组装，</span>AcitveX<span style="font-family: '微软雅黑','sans-serif'">控件</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt"><span>&#9314;<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span><span style="font-family: '微软雅黑','sans-serif'; letter-spacing: 0.4pt">、分布式：事务逻辑和系统服务相分离</span><span style="letter-spacing: 0.4pt">,</span><span style="font-family: '微软雅黑','sans-serif'; letter-spacing: 0.4pt">简化了系统开发的复杂性，</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt"><span>&#9315;<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span><span style="font-family: '微软雅黑','sans-serif'; letter-spacing: 0.4pt">、组件需要动态连接，，不可能在运行时编译。</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt"><span>&#9316;<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span><span style="font-family: '微软雅黑','sans-serif'; letter-spacing: 0.4pt">、要封装，不要改变其接口、</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 0pt 18pt"><span>&#9317;<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span><span style="font-family: '微软雅黑','sans-serif'; letter-spacing: 0.4pt">、以二进制的形式发布，已编译好的。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 10pt 36pt"><span>2、<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: '微软雅黑','sans-serif'">接口：提供两个不同对象间的一种连接，计算机是通过一组函数连接起来的，其实这组函数实质上就是定义了程序中不同部分的接口。对于</span>COM<span style="font-family: '微软雅黑','sans-serif'">接口是包含一个函数指针数组的内存结构。</span></p>
<p style="text-indent: 36pt; margin: 0cm 0cm 10pt"><span style="font-family: '微软雅黑','sans-serif'">用纯虚函数作为接口。看下面经典例子：</span></p>
<p><span style="font-size: 10.5pt">#define&nbsp;InSruct&nbsp;struct</span></p>
<p><span style="font-size: 10.5pt">InSruct&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 10.5pt">定义接口</span></p>
<p><span style="font-size: 10.5pt">{</span></p>
<p><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual void Fun1()=0;</span></p>
<p><span style="font-size: 10.5pt">}; </span></p>
<p>&nbsp;</p>
<p><span style="font-size: 10.5pt">class CA:public&nbsp;IA&nbsp;&nbsp;&nbsp;&nbsp; //</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 10.5pt">定义组件（注意类可以继承结构体，结构体也能继承结构体）</span></p>
<p><span style="font-size: 10.5pt">{</span></p>
<p><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void Fun1()</span></p>
<p><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout&lt;&lt;"class Fun1()";</span></p>
<p><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p><span style="font-size: 10.5pt">};</span></p>
<p><span style="font-size: 10.5pt">Void&nbsp;main()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></p>
<p><span style="font-size: 10.5pt">{</span></p>
<p><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CA *pCa=new CA;</span></p>
<p><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IA *pIa=pCa;</span></p>
<p><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pIa-&gt;Fun1();&nbsp;&nbsp; //</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 10.5pt">表示接口：在程序内部实现。</span></p>
<p><span style="font-size: 10.5pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete pCa;</span></p>
<p><span style="font-size: 10.5pt">}</span></p>
<p>&nbsp;</p>
<p><span style="font-size: 10.5pt">//</span><span style="font-family: '微软雅黑','sans-serif'; font-size: 10.5pt">特别注意的是：类不是组件，组件不一定要类实现，也不不一定需要继承、</span></p>
<p>&nbsp;</p>
<p>&nbsp;<span style="font-family: 'Tahoma','sans-serif'; font-size: 11pt; mso-fareast-font-family: 微软雅黑; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA" lang="EN-US"><v:shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600">&nbsp;<img border="0" alt="" src="http://www.cppblog.com/images/cppblog_com/cass/组件与接口1.jpg" width="583" height="617" /><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype></span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p style="text-indent: -36pt; margin: 0cm 0cm 10pt 36pt"><span>3、<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: '微软雅黑','sans-serif'">组件的内存（探讨</span>COM<span style="font-family: '微软雅黑','sans-serif'">接口为什么可以用纯抽象基类实现</span>COM<span style="font-family: '微软雅黑','sans-serif'">组件）</span></p>
<p style="margin: 0cm 0cm 10pt"><span style="font-family: '微软雅黑','sans-serif'">抽象基类提供</span>vtbl<span style="font-family: '微软雅黑','sans-serif'">指针指向虚拟函数、每个对象共享同一个</span>vtbl<span style="font-family: '微软雅黑','sans-serif'">指针，但数据各自不同</span></p>
<p style="margin: 0cm 0cm 10pt"></p>
<p style="margin: 0cm 0cm 10pt">//////////////////////////////////////////////////////////////////////////////////////////////</p>
<p style="margin: 0cm 0cm 10pt"></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 10pt 36pt"><span>4、<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: '微软雅黑','sans-serif'">客户通过不断询问清晰组件干什么，但没有完成知道组件内部怎么样。</span></p>
<p style="margin: 0cm 0cm 10pt"><span style="font-family: '微软雅黑','sans-serif'">客户如何向组件询问关于它所支持的接口？组件如何回答、以及这种请求应答方式的结果、</span></p>
<p style="margin: 0cm 0cm 10pt">&nbsp;</p>
<p style="margin: 0cm 0cm 10pt">&nbsp;</p>
<p style="margin: 0cm 0cm 10pt">&nbsp;</p>
<p style="text-indent: -18pt; margin: 0cm 0cm 10pt 18pt"><span>&#9312;<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span><span style="font-family: '微软雅黑','sans-serif'">、</span><span style="letter-spacing: 0.4pt">HRESULT <strong>QueryInterface</strong>( REFIID <em>iid</em>, void** <em>ppvObject</em>);</span><span style="font-family: '微软雅黑','sans-serif'; letter-spacing: 0.4pt">函数查询某个组件是否支持某个特定的接口</span></p>
<p style="margin: 0cm 0cm 10pt"><span style="letter-spacing: 0.4pt">//iid </span><span style="font-family: '微软雅黑','sans-serif'; letter-spacing: 0.4pt">是要查询的接口</span><span style="letter-spacing: 0.4pt">ID,&nbsp;<em>ppvObject</em></span><span style="font-family: '微软雅黑','sans-serif'; letter-spacing: 0.4pt">是返回的接口的指针，</span></p>
<p style="text-indent: -18pt; margin: 0cm 0cm 10pt 18pt"><span>&#9313;<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span><span style="font-family: '微软雅黑','sans-serif'">关于类型转换：</span></p>
<p><span style="font-family: 宋体; font-size: 15pt">static_cast</span></p>
<p><span style="font-family: '微软雅黑','sans-serif'">　</span><span style="font-family: 宋体; font-size: 10.5pt">用法：static_cast &lt; type-id &gt; ( expression ) </span></p>
<p><span style="font-family: 宋体; font-size: 10.5pt">　　<span style="color: red">该运算符把expression转换为type-id类型</span>，但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法： </span></p>
<p><span style="font-family: 宋体; font-size: 10.5pt">　　</span><span style="font-family: 宋体; font-size: 10.5pt">&#9312;</span><span style="font-family: 宋体; font-size: 10.5pt">用于类层次结构中基类（父类）和<a href="http://baike.baidu.com/view/535532.htm" target="_blank"><span style="color: #136ec2"><span>派生类</span></a></span>（子类）之间指针或引用的转换。 </span></p>
<p><span style="font-family: 宋体; font-size: 10.5pt">　　进行上行转换（把派生类的指针或引用转换成基类表示）是安全的； </span></p>
<p><span style="font-family: 宋体; font-size: 10.5pt">　　进行下行转换（把基类指针或引用转换成派生类表示）时，由于没有动态类型检查，所以是不安全的。 </span></p>
<p><span style="font-family: 宋体; font-size: 10.5pt">　　</span><span style="font-family: 宋体; font-size: 10.5pt">&#9313;</span><span style="font-family: 宋体; font-size: 10.5pt">用于基本数据类型之间的转换，如把int转换成char，把int转换成enum。这种转换的安全性也要开发人员来保证。 </span></p>
<p><span style="font-family: 宋体; font-size: 10.5pt">　　</span><span style="font-family: 宋体; font-size: 10.5pt">&#9314;</span><span style="font-family: 宋体; font-size: 10.5pt">把空指针转换成目标类型的空指针。 </span></p>
<p><span style="font-family: 宋体; font-size: 10.5pt">　　</span><span style="font-family: 宋体; font-size: 10.5pt">&#9315;</span><span style="font-family: 宋体; font-size: 10.5pt">把任何类型的表达式转换成void类型。 </span></p>
<p><span style="font-family: 宋体; font-size: 10.5pt">　　注意：static_cast不能转换掉expression的const、volitale、或者__unaligned属性。 </span></p><img src ="http://www.cppblog.com/Cass/aggbug/156462.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Cass/" target="_blank">Yu_</a> 2011-09-21 19:54 <a href="http://www.cppblog.com/Cass/archive/2011/09/21/156462.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>与其他程序通信 FindWindow </title><link>http://www.cppblog.com/Cass/archive/2011/04/11/143921.html</link><dc:creator>Yu_</dc:creator><author>Yu_</author><pubDate>Mon, 11 Apr 2011 02:53:00 GMT</pubDate><guid>http://www.cppblog.com/Cass/archive/2011/04/11/143921.html</guid><wfw:comment>http://www.cppblog.com/Cass/comments/143921.html</wfw:comment><comments>http://www.cppblog.com/Cass/archive/2011/04/11/143921.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Cass/comments/commentRss/143921.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Cass/services/trackbacks/143921.html</trackback:ping><description><![CDATA[<span style="WIDOWS: 2; TEXT-TRANSFORM: none; TEXT-INDENT: 0px; BORDER-COLLAPSE: separate; FONT: medium Simsun; WHITE-SPACE: normal; ORPHANS: 2; LETTER-SPACING: normal; COLOR: rgb(0,0,0); WORD-SPACING: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px" class=Apple-style-span><span style="TEXT-ALIGN: left; LINE-HEIGHT: 21px; FONT-FAMILY: 宋体; FONT-SIZE: 12pt" class=Apple-style-span>
<p style="PADDING-BOTTOM: 0px; MARGIN: 1em 0px 0.5em; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">通常我们做的程序不应该只局限于程序间的操作。也许能对电脑上其他的程序操作会更有意思。我们能做到，也很容易做到、使用</p>
<p style="PADDING-BOTTOM: 0px; MARGIN: 1em 0px 0.5em; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><a style="COLOR: rgb(51,102,153); TEXT-DECORATION: none" name=_win32_findwindow></a>FindWindow。</p>
<p style="PADDING-BOTTOM: 0px; MARGIN: 1em 0px 0.5em; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><code style="FONT-STYLE: normal"><strong>HWND FindWindow( LPCTSTR</strong><em style="FONT-STYLE: italic"><span class=Apple-converted-space>&nbsp;</span>lpClassName</em><strong>,<span class=Apple-converted-space>&nbsp;</span></strong>// pointer to class name<span class=Apple-converted-space>&nbsp;</span><strong>LPCTSTR</strong><em style="FONT-STYLE: italic"><span class=Apple-converted-space>&nbsp;</span>lpWindowName</em><span class=Apple-converted-space>&nbsp;</span>// pointer to window name<span class=Apple-converted-space>&nbsp;</span><strong>);</strong></code></p>
<p style="PADDING-BOTTOM: 0px; MARGIN: 1em 0px 0.5em; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><span style="LINE-HEIGHT: 21px; FONT-FAMILY: mceinline">推荐使用</span><strong>HWND FindWindowEx(</strong></p>
<p style="PADDING-BOTTOM: 0px; MARGIN: 1em 0px 0.5em; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><strong>HWND</strong><em style="FONT-STYLE: italic"><span class=Apple-converted-space>&nbsp;</span>hwndParent</em><strong>,</strong>// handle to parent window</p>
<p style="PADDING-BOTTOM: 0px; MARGIN: 1em 0px 0.5em; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><strong>HWND</strong><em style="FONT-STYLE: italic"><span class=Apple-converted-space>&nbsp;</span>hwndChildAfter</em><strong>,<span class=Apple-converted-space>&nbsp;</span></strong>// handle to a child window</p>
<p style="PADDING-BOTTOM: 0px; MARGIN: 1em 0px 0.5em; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><strong>LPCTSTR</strong><em style="FONT-STYLE: italic"><span class=Apple-converted-space>&nbsp;</span>lpszClass</em><strong>,<span class=Apple-converted-space>&nbsp;</span></strong>// pointer to class name</p>
<p style="PADDING-BOTTOM: 0px; MARGIN: 1em 0px 0.5em; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><strong>LPCTSTR</strong><em style="FONT-STYLE: italic"><span class=Apple-converted-space>&nbsp;</span>lpszWindow<span class=Apple-converted-space>&nbsp;</span></em>// pointer to window name<span class=Apple-converted-space>&nbsp;</span><strong>); &nbsp;功能更加强大。</strong></p>
<p style="PADDING-BOTTOM: 0px; MARGIN: 1em 0px 0.5em; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><strong><strong>FindWindowEx 能根据多种条件查找。</strong></strong></p>
<h2 style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px"><strong><strong>1、</strong></strong>hwndParent &nbsp; 父窗口</h2>
<h2 style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">2、hwndChildAfter &nbsp;兄弟窗口</h2>
<h2 style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">3、lpszClass &nbsp; 特定字符串</h2>
<h2 style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">4、lpszWindow &nbsp;或者窗口的标题。</h2>
<h2 style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">当你仅知道要通信窗口的某一情况时，便可以查找到。</h2>
<p style="PADDING-BOTTOM: 0px; MARGIN: 0px; PADDING-LEFT: 0px; PADDING-RIGHT: 0px; PADDING-TOP: 0px">推荐使用小工具<br><img border=0 alt="" src="http://www.cppblog.com/images/cppblog_com/cass/22.jpg" width=522 height=416><br><br>能快速查找出你电脑的应用程序的类名与标题、</p>
</span></span>
<img src ="http://www.cppblog.com/Cass/aggbug/143921.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Cass/" target="_blank">Yu_</a> 2011-04-11 10:53 <a href="http://www.cppblog.com/Cass/archive/2011/04/11/143921.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>