<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8972319</id><updated>2011-12-14T18:35:23.872-08:00</updated><title type='text'>TeleStar's Notes</title><subtitle type='html'>This blog backups some of my notes on programming and related issues. It also contains some poems and lyrics (though not written by myself)that express my feelings. Since Chinese and Japanese texts are used in many posts, you'd better to install Asian Language Package to read them smoothly. Without proper rendering support, you may see question marks, boxes, or other symbols instead of Chinese characters. If you think this blog is useful, please help click the Google Ads on the left.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://telestarnotes.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default?start-index=101&amp;max-results=100'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>350</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8972319.post-3263418689960957359</id><published>2009-02-12T03:35:00.000-08:00</published><updated>2009-02-12T03:36:39.029-08:00</updated><title type='text'>Some notes on Computation Library - 1</title><content type='html'>1.&lt;br /&gt;from http://cmsir.scinese.com/2008/02/22/using-lapack-in-c/&lt;br /&gt;&lt;br /&gt;Using LAPACK in C/C++&lt;br /&gt;&lt;br /&gt;Fortran是科学计算的标准语言，无论是性能，库，还是普及程度都勿庸置疑地是老大。作为最古老的计算机语言，这么多年的积累让其它语言几乎没可能改变这一局面。可惜我在大学时只学了C，这得怪我们系里的课程安排……无奈之下，很多时候只能C + Fortran Library来干活。最常用的Fortran库无疑是Lapack，主要就是各种对角化。这篇文章里就把C/C++中调用Lapack的每一个细节都记录下来，主要目的是让我下次编程时可以不用重复回忆（我已经吃过一次亏了，花了一晚上时间来研究怎么在C/C++里面链接dll这种白痴问题）。如果有朋友也碰到类似的问题，而又碰巧看到了这篇文章（这是小概率事件，google虽然触角无数，但也难以伸到我这网络深处的小地方），也许可以帮你少走些弯路。&lt;br /&gt;&lt;br /&gt;言归正传。首先我们假设工作的平台是Windows（bs我吧……）。C++编译器我只对Microsoft Visual C++ 8.0（即Visual Studio 2005)和MinGW gcc/g++比较熟悉，所以也就只包括这两种。如果你想从源码编译Lapack，那么还得有一个Fortran编译器（如果是这样，建议直接用Fortran）。对于大部分懒人，从网上直接Down一个编译好的库就可以了。例如去下面这个网页：&lt;br /&gt;&lt;br /&gt;LAPACK &amp; BLAS precompiled binaries for Win32 platform&lt;br /&gt;&lt;br /&gt;http://www.fi.muni.cz/~xsvobod2/misc/lapack/&lt;br /&gt;&lt;br /&gt;注意下载shared version，static version需要Intel Fortran 9.0的一些库支持。此外，别忘了下载底下的头文件。按照C的惯例，把库文件解压到lib目录，头文件到include目录。库当中除了lapack_win32.dll还有一个叫blas_win32.dll的东西，包括Lapack需要的一些函数，就我们的目的而言，直接无视它就可以。&lt;br /&gt;&lt;br /&gt;在开始进入如何编译链接这种糙活之前，先简单介绍几个最常用的矩阵对角化库函数。就我个人而言，要对角化的几乎都是Hermitian矩阵，或者是实对称矩阵。前者一般zheev函数足够解决问题，后者通常是dsyev。在include目录下都有相应名字的头文件。遗憾的是，这些函数的声明都相当吓人，动辄十来个参数，一个一个对着是看什么意思都能把人累死。所以地球上就有好心人做了wrap，在声明上再加一层接口，大大简化了我们的使用。比如&lt;br /&gt;&lt;br /&gt;LAPACK/ARPACK Header Files&lt;br /&gt;&lt;br /&gt;http://www-heller.harvard.edu/people/shaw/programs/lapack.html&lt;br /&gt;&lt;br /&gt;由于是跨语言调用，虽然我们使用的是二进制级的代码，但仍然需要注意C/C++和Fortran底层的一些差别。第一点区别是数据类型。简单地说，C/C++中的单精度浮点数float类型相当于Fortran的real，double相当于doublereal。而Fortran中的complex和doublecomplex则可以用C++标准库中的std::complex及std::complex代替。C里面需要我们自己定义一个struct：&lt;br /&gt;&lt;br /&gt;typedef struct {&lt;br /&gt;  double r, i;&lt;br /&gt;}doublecomplex;&lt;br /&gt;除了数据类型的转换，最主要的一点是二维数组在内存中的布局：C/C++是按行存放的，而Fortran是按列存放的。对于实对称矩阵或者Hermitian矩阵，问题倒也不大。一般来说只要在把C/C++数组传入Lapack函数前做一个转换即可。&lt;br /&gt;&lt;br /&gt;写完了程序，我们可以开始编译了。为了让编译器能找到头文件，需要在选项中添加头文件的搜索目录。对Visual C++，相应的命令行选项是/I。例如说Lapack的头文件都在C:\LAPACK\include，那么就必须在微软的C++编译器cl调用时加上命令行参数 /I “C:\LAPACK\include”。由于IDE的发达，用VC++干活的人几乎不可能直接面对命令行；在Visual Studio里面，打开工程属性对话框，在配置属性-&gt;C/C++-&gt;常规-&gt;附加包含目录中设置一下即可。对于gcc，命令行参数是-IC:\LAPACK\include。&lt;br /&gt;&lt;br /&gt;下面的问题是如何在C程序中链接dll。如果你用的是MinGW，恭喜你，这个问题几乎不成为一个问题：只要在最后链接时命令行里添上dll文件名（下面会有一个完整的例子）。如果是Visual C++，事情要复杂一些。光一个dll文件Visual C++还链接不动，你还得有一个lib文件来告诉它dll中都导出(export)了哪些函数。还有一个选择是在代码里面用LoadLibrary这个API动态加载。当然，无论如何微软在这件事上都做得比较煞笔，但是我们没有办法，只好照办之。注意，刚才下载的压缩包中已经包含了相应的lib文件了，但是我自己用下来发现里面的lapack_win32.lib有些问题。没有办法，我们只好DIY到底，自己generate一个。从dll生成lib网上这类工具很多，如果你偷懒也可以直接我自己做的。做好了lib以后，先在工程属性对话框-&gt;配置属性-&gt;链接器-&gt;常规-&gt;附加库目录里设置一下你的dll和lib的所在地（正常人会把它们放在一块）。然后配置属性-&gt;链接器-&gt;输入-&gt;附加依赖项中把要链接的Lib文件名写上（这里就是lapack.lib)。这些都设置好了，如果你的程序没有问题，编译应该能够通过了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-3263418689960957359?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/3263418689960957359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/3263418689960957359'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2009/02/some-notes-on-computation-library-1.html' title='Some notes on Computation Library - 1'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-7090507157248689172</id><published>2009-01-02T04:32:00.000-08:00</published><updated>2009-04-15T06:47:57.428-07:00</updated><title type='text'>Why I maintian such a blog</title><content type='html'>下面的这些转贴至少解释了其中一部分原因&lt;br /&gt;&lt;br /&gt;1.&lt;br /&gt;from http://blog.farmostwood.net/65.html&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;在未名上看到一片帖子：《兀自燃烧的句子》。里面长长的一段话，让人忍不住想抄下来：&lt;br /&gt;&lt;br /&gt;……我却由此想到另外一个问题：引文和原文之间确实有非常奇妙的关系。有时我们在一篇冗长的论文中发现了作者引用的诗句，就像在一片沙漠中发现一片绿洲那样感到惊喜。这些诗句显得那么生动、新鲜，于是我们迫不及待地去寻找整首诗，结果往往会大失所望。在一片单调的绿色中，几丛灌木并不会引起我们的兴趣。当然，被人引用的往往都是佳句，但恐怕也不能排除那种猝然相见宛然如在目前所产生的心理效果。……而在另外一些时候，我们从我们读过的书中摘抄各种我们觉得精彩、聪明、奇妙的语言，希望它们永远地为我们所拥有，永远保持着鲜亮的光泽，并在适当的时候被我们用来装点自己枯燥无味的文字。然而，这些被分割出来的句子似乎并不能经得起反复的阅读，它们很快就枯萎了，褪去了先前的光泽，像被嚼干的口香糖一样无味。当我们想占有它们的时候，我们已经失去了它们。而原书则依然焕发着蓬勃的生机。借用博尔赫斯的说法，为了保存一滴晶莹剔透的水珠，不忍心看它干涸，我们还是把它放回大海吧，虽然我们只能观看而不能拥有大海。本雅明说过他想写一本完全用引文构成的书，我对他只有佩服的份，因为他竟然自己收集水滴来创造一片大海。&lt;br /&gt;&lt;br /&gt;好一个“猝然相见，宛然如在目前”！那是阅读时最大的快乐之一。那些优美、精准、凝练的文字透过别人的引用，叮叮咚咚地落在心上，仿佛在眼前打开了一扇朝着花园却只能瞥见繁华一角的窗子一般，让人心旷神怡而又意犹未尽。——尽管经验告诉我们那花园的全貌也许其实要令人失望的。于是想起我的那个被无数人探询的签名档，“跟个孩子似的相信”。“真棒啊”，他们说，“哪里找来的？”当年我也这么探问锦来着，锦笑着说：“相信我，全文里就那么一段是精华。”我去找了，果然。&lt;br /&gt;&lt;br /&gt;然而那些“兀自燃烧的句子”们还是让我一次又一次惊喜着。我由衷地喜爱它们，期望自己也能将文字驯服的那样妥帖。常常眼睁睁的看着自己写下的句子呈现出自己不能容忍的乏味和愚蠢，于是陷入无边的沮丧里，可是越是意识到不能满足，那种审美上的强迫感就越是强烈。在这种情况下，阅读那些清新的、生机勃勃的、像冬日的阳光一样明亮温暖的文字就变得梦境般的美妙起来。如果大海离得太过遥远，那么至少请允许我透过一滴水珠来幻想海风的味道吧。&lt;br /&gt;&lt;br /&gt;“忽然间竟有强烈想要说话的欲望，但其实说什么？似乎曾有句子唇边含过，可惜含久了，便忘了它的长短字数，生出一点不是非说不可的犹豫。都是自己每日长久温习反复咂嗼的甘与苦，真出了口，跟假的似的，反倒有过分言重流于做作的嫌疑。于是只有沉默，接着沉默，我总是失语在真正最想说话的时刻。”&lt;br /&gt;&lt;br /&gt;——《跟个孩子似的相信》&lt;br /&gt;&lt;br /&gt;2.&lt;br /&gt;from http://blog.csdn.net/pongba/archive/2009/02/16/3896311.aspx&lt;br /&gt;&lt;br /&gt;为什么你应该（从现在开始就）写博客收藏&lt;br /&gt;（一）为什么你应该（从现在开始就）写博客 &lt;br /&gt;&lt;br /&gt;用一句话来说就是，写一个博客有很多好处，却没有任何明显的坏处。（阿灵顿的情况属于例外，而非常态，就像不能拿抽烟活到一百岁的英国老太太的个例来反驳抽烟对健康的极大损伤一样）&lt;br /&gt;&lt;br /&gt;让我说得更明确一点：用博客的形式来记录下你有价值的思考，会带来很多好处，却没有任何明显的坏处。Note：碎碎念不算思考、心情琐记不算思考、唠唠叨叨也不算思考、没话找话也不算思考，请以此类推。&lt;br /&gt;&lt;br /&gt;下面是我个人认为写一个长期的价值博客的最大的几点好处：&lt;br /&gt;&lt;br /&gt;1) 能够交到很多志同道合的朋友。我自己既写博客，也读别人的博客，在这个时代，对于生活中的绝大多数人来说，拓宽朋友圈子的途径几乎只有一个，通过网络，而如何在网络中寻找到气味相投的朋友，如何判断别人和自己是否有共同语言？显然，通过天天在SNS上碎碎念的那些日记是难以做到的。我佩服的一些朋友几乎全都是长期用博客记录想法的人，因此，和他们即便不打照面，也是心照不宣。即便素未谋面也能坐下来就聊得热火朝天。&lt;br /&gt;&lt;br /&gt;为什么博客在结交志同道合的朋友方面的潜力要远胜于原始的交谈方式？很简单，第一，博客无地域限制，整个互联网上从A到B只有一个点击的距离，而传统的建立朋友圈子的方法则受到地域限制。第二，也是更重要的一点，即如果按照以前结交朋友的方式，需要互相聊天，交流观点，然后才逐渐熟悉起来，这需要一个较长的过程，而且更糟糕的是，当你遇到另一个陌生人，又要把整个过程重复一次，表达你已经对老友表达过的那番想法。可博客却做到了“一次表达，无数次阅读”，当我看到一个写了好几年的博客，看完了之后我仿佛和这个人交谈了很久，用程序员们喜欢听的话来说就是，“博客极大地增强了话语的复用性”。&lt;br /&gt;&lt;br /&gt;我曾在CSDN上写了近六年的博客，在一年半前建立了一个Google Groups（TopLanguage），由于我的博客的长期阅读者都是互相有共同语言的，因此这个Group一开始就热火朝天，而高质量的技术讨论则进一步吸引了更多的牛人的参与，雪球滚起来之后，就很难停下来了，将近一年半下来，从这个Group的讨论中我获益良多[1]。而对于非程序员朋友，科学松鼠会则是一个很好的例子。&lt;br /&gt;&lt;br /&gt;2) 书写是为了更好的思考。我在《书写是为了更好的思考》里面详细总结了书写的好处，这里就不拷贝粘贴了。&lt;br /&gt;&lt;br /&gt;3) “教”是最好的“学”。如果一件事情你不能讲清楚，十有八九你还没有完全理解。绝大多数人应该都知道在程序员行业面试官经常要求你讲解一个东西给他听，他会说他不懂这个东西（他如果真的不懂的话效果其实是最好的），而你的任务则是说到让他理解为止。&lt;br /&gt;&lt;br /&gt;为了让一个不明白的人做到明白，你必须要知道从明白到不明白他究竟需要掌握哪些概念，这就迫使我们对我们大脑中整个的知识体系来个寻根究底，把藏在水面之下的那些东西统统挖出来，把大脑中的那些我们知道、但不知道自己知道的潜在概念或假设（assumptions）都挖出来，把它们从内隐记忆拉扯到外显记忆中。因为只有完全知道、并知道自己知道一切来龙去脉的人，才能真正把一件事情讲得通通透透。&lt;br /&gt;&lt;br /&gt;但是，你可能会怀疑，那除了能够讲清楚之外，弄清自己到底知道哪些东西还有其他什么好处吗？如果没有其他好处，那我又何必费这个劲呢？我又不当老师。&lt;br /&gt;&lt;br /&gt;TopLanguage上的一位朋友sagasw曾经讲了这样一个小故事：据说在某个著名软件公司里，开发组的桌上会放着一只小熊，大家互相问问题之前，先对着小熊把问题说一遍，看能不能把问题描述的清晰，基本上说的比较有条理以后，答案也就随之而来了。当然，你不一定要对小熊说，你可以在大脑中虚构一个听众，一个不懂行的听众，然后你说给他听。这是可行的，我经常在路上用。不过如果你能坐下来，我建议你还是说给实际的听众听——即写下你的思考，因为书写是更好的思考。&lt;br /&gt;&lt;br /&gt;我们的绝大多数知识在绝大多数时候都隐藏在潜意识中，其实我们意识的窗口很小，我们的工作记忆只能容纳寥寥数个条目（记得那个“看你能够记住屏幕上同时闪现的多少个数字”的flash小游戏吗？），我们平时所作的推理过程很大部分都是自动的，发生在潜意识中，而我们只能感知到一些中间结论。不信你回忆一下你在和别人讨论问题的时候有多少次觉得“反正就是这样，我感觉得到它是对的，但是你问我，我也说不清到底怎么回事”，对此你不觉得很奇怪吗？如果你都不能从逻辑上支持你的结论，你怎么就能确信它是对的呢？仅仅因为你的直觉强烈地告诉你它是对的？那如果旁边有另一个人，他和你持相反的观念，而他的直觉也强烈地告诉他他是对的。这时候你又怎么想？“他的直觉错了，我的直觉是对的”？难道你这么自信你的直觉是世界上最可靠的？&lt;br /&gt;&lt;br /&gt;我自己则是非常珍惜类似这样的机会，即当“我强烈地觉得它是对的，但我却说不出所以然来”，这时候往往是到大脑中翻箱倒柜的时候，弄清来龙去脉的时候，深入反思的时候，纠正一直以来错误的潜在前提假设的时候。另一方面，“我强烈地觉得这个说法有问题，但我却说不清它为什么有问题，到底哪有问题”，这也是一个极有意义的瞬间，它几乎总是意味着你对一个问题的认识有潜在的偏差，肯定是在你自己都没有觉知到的地方引入了一个潜在的假设、偷换了一个重要的概念，等等。而这种时候就是深入反思的时候，当你终于潜到问题的底层，触摸到问题的实质，把水面之下的冰山整体看清了的时候你会有一种通体舒泰的感觉。&lt;br /&gt;&lt;br /&gt;为什么说以上这些？因为刚才说的是你必须等待这样的反思机会，但如果你选择经常总结自己的知识体系，并说出来给你的读者听，你就会发现你自己创造了这样的机会。如果我们平时不反思，我们觉得很多事情都是当然的，但结果如果要你一开口说给别人听，常常会发现事情就开始变得不那么明显了，你说着说着，就开始莫名其妙地发现自己需要用到“反正”这个词了。&lt;br /&gt;&lt;br /&gt;于是，反思的机会就来了。&lt;br /&gt;&lt;br /&gt;一旦你把自己潜意识里面的东西从幕后拉出来，你就有了面对并反思它们的可能，而不是任它们在幕后阴险地左右你的思维。很多时候我们的思路出了问题并不是我们不会反思，而是不知道自己的思维中有那些隐含的假设（assumptions），如果你只感觉到答案，却不知道你大脑得到这个答案之前做了哪些推理，你又怎么知道哪一环可能出了问题呢？另一方面，一旦你弄清了自己到底是怎么想的，离意识到问题就不远了，很简单的道理——如果别人和你争辩的时候总是只摆立场，你就很难和他辩，但如果他把自己的推理过程原原本本暴露给你，批判起来总是容易得多的。（也正因为这个原因有很多人总是把逻辑藏在背后，不敢暴露出来）&lt;br /&gt;&lt;br /&gt;绝大多数时候其实我们都会不假思索地得出一些结论，就像上了发条的自动机，但其实我们并不知道这些结论到底怎么来的，在思维的背后到底发生了哪些事情，故而当我们发现我们的结论错了的时候，一头雾水，没法着手寻找到底在哪错了。如果你注意一下很多人的发言（论坛、博客等等），如果你把他们的发言分为“前提”、“假设”、“逻辑”、“结论”这四个部分，你会发现一大堆人只会不停地下结论，摆立场，却见不到这些结论或离场的前提、假设和个中逻辑，倒也不是他们不愿意写出逻辑，而是因为反思自己的思维过程实在是一件困难非常的事情，我们的推理过程很大一部分发生在意识的水面之下，只有当有了重要结论的时候这条逻辑链才会浮出来冒一个泡，让我们的意识捕捉到。更何况绝大多数时候我们用的其实并不是完整严密的逻辑思维，而是思维捷径。&lt;br /&gt;&lt;br /&gt;去教一个完全不懂的人，则是一种最最强大和彻底的反思途径——因为他没有任何预备的知识，所以要让他弄懂你所知道的，你就必须彻底反思你的知识体系，弄清这座大厦的根基在什么地方，弄清它的骨架在什么地方，一砖一瓦到底是怎么垒起来的，你不能自己站在11层上，然后假设你的读者站在第10层，指望着只要告诉他第11层有那些内容就让他明白。你的读者站在第一层，你必须知道你脚下踩着的另外10层到底是怎么构造的。这就迫使你对你所掌握的、或之前认为正确的那些东西作彻彻底底的、深刻的反思，你的受众越是不懂，你需要反思得就越深刻。&lt;br /&gt;&lt;br /&gt;4) 讨论是绝佳的反思。另一方面，很多时候我们并不是有机会说给完全不懂的人听，更大的可能性是说给同领域有一定基础的人听，这个时候并不代表就不能促使反思了，实际上，你会发现，如果你公开你的想法，几乎总能看到与你持不同意见的人，然后你通过比较你和他的观念之间的差别，会发现你们在一开始的思路上就存在差异，差异从哪里来的？在进一步讨论中你们就会不断地迫使对方拿出更深层次的理由，这同样也是一种非常有效地促使自己反思的方法，在讨论的过程中双方的理由自然会变得越来越深入，越来越接近问题的本质，一些平时难以注意到的深层面的差异性就会逐渐浮现出来，你也就多了一次难得的机会去审视自己的思维中到底存放了哪些错误的信息。&lt;br /&gt;&lt;br /&gt;5) 激励你去持续学习和思考。如果你没有持续学习和思考的习惯，你的博客很快就会没有内容可写，就只能整点碎碎念或者转载，然后你就会失去读者，然后你就会关掉博客，然后一旦关掉博客之后你也就死了写博客的心，然后就少了一条激励你去思考和总结的途径，然后你变得更不高兴总结和思考，然后… &lt;br /&gt;&lt;br /&gt;为了打破这个死循环，不要永久停止更新你的博客，就算你两个月，三个月都不写，只要你每篇都是写自己思考的产物，写有价值的东西，在互联网上，金子的确总是会发光的，因为有无数的信息聚合平台在期待这些有价值的内容，有搜索引擎为你的内容提供海量的潜在读者，有海量的人肉在手动挖掘和转载那些有价值的东西。我们所能做的最差的一个决策莫过于停止做一件没有任何坏处，却有一大堆好处的事情。&lt;br /&gt;&lt;br /&gt;为了让你的博客有价值，你必须不断总结自己学习的结果，你必须不断思考，给出比别人深刻、独到的见解。这看起来有点本末倒置，但很快本和末就会正过来。&lt;br /&gt;&lt;br /&gt;6) 学会持之以恒地做一件事情。很多人在生活中容易觉得迷失，不知道想要做什么，是因为没有一件能够持续地做的事情，用俗话来说就是没有主心骨。用积极心理学的话来说就是没有一件能够创造流体验的事情，而书写自己的思想则是一件容易产生流体验的事情，在书写的时候，特别是理性地书写的时候，大脑逐渐进入推理分析模块，一切不愉快的情绪，烦躁感都会逐渐消隐下去。不过前提是你得开始，并且坚持过一开始的困难期，以后的一切便成了习惯成自然。&lt;br /&gt;&lt;br /&gt;7) 一个长期的价值博客是一份很好的简历。这里的“简历”并非是狭义上的求职简历，毕竟现在还没有到价值博客的时代，很多人写博客都是到处转载或者干脆碎碎念，正因此面试官未必拿个人博客当成了解一个人的更可靠窗口。这里的“简历”是指一个让别人了解自己的窗口，虽然我们未必做得到像罗永浩、Keso这样的博客，个人的影响力已经足以支撑出一份事业（牛博和5gme），但至少你会因此而结识更多的人，你的博客价值越高，你结识的人就越牛，跟牛人交流又会让你的眼界得到极大的开阔，打开一扇又一扇你原本不知道的门，于是你就变得更牛… 这是一个良性循环。&lt;br /&gt;&lt;br /&gt;（二）怎么做到长期写一个价值博客&lt;br /&gt;&lt;br /&gt;注意到我并没有说“怎么做到长期坚持写一个价值博客”，因为当思考和总结成为习惯之后，诉诸文字以及借助书写来进一步思考就变成了一件自然而然的事情，就变成了一件“因为你在思考和总结从而必须书写下来”的事情，博客就变成了副产品。&lt;br /&gt;&lt;br /&gt;一开始的时候你是因为要写博客而去使劲地思考和总结，指望给出令人眼睛一亮的东西，到了后来，就变成了因为你习惯了思考和总结，因为你意识到书写是更好的思考，你就必须使你的想法成为文字。至此本和末就会各归原位，不再颠倒。&lt;br /&gt;&lt;br /&gt;怎样做到长期写一个价值博客？也许有人会给出很多有趣有用的小技巧来提供动机和激励，譬如如何做SEO，如何鼓励读者留言等等，但是这些我都不想说，我只想说最最重要的，那就是：&lt;br /&gt;&lt;br /&gt;让你自己成为一个持续学习和思考的人，并只写你真正思考和总结之后的产物，其他一切就会随之而来。&lt;br /&gt;&lt;br /&gt;就像那句经常被人传阅的话：只做你最感兴趣的事情，钱会随之而来[2]。&lt;br /&gt;&lt;br /&gt;这方面的具体例子大家可以留意一下，随处可见，就不一一举了。我想再重复一下的是，千万不要碎碎念，我能理解每个人都想偶尔发发牢骚的冲动，但是现在已经有了一个很好的窗口：twitter，所以立即停止在你的博客上碎碎念，阅读博客的人希望得到信息而非噪音。如果实在忍不住想碎碎念的话不妨换一下位置，这么来告诉自己：如果你看到别人博客来上这么一段，你会有兴趣看吗？&lt;br /&gt;&lt;br /&gt;（三）可能出现的问题以及怎样应付&lt;br /&gt;&lt;br /&gt;即便上文给出了N条写博客的理由，但有时候只要一条不写的理由就会让人停止做一件事情。所以我特别加上一节“可能出现的问题以及怎样应付”，《影响力2》[3]第五章雄辩地证明，“Much of Will is Skill”，意志力很大程度上来源于有正确的方法，而非天生。&lt;br /&gt;&lt;br /&gt;1) 担心别人认为没有价值。事实是，你面临过的问题总会有人面临过，你独立思考了，别人没有，你的文章对他们就会有价值。当然，肯定会对某些人没有价值，他们早就知道了，但就算你再厉害，也总是有人比你厉害的，不能说因为这些原因就不记录你自己的想法了，你自己思考了之后理解得最深刻，就算有别人想过了，总有人没有想到的。况且，思考成了习惯，你的思考能力也会越来越强，你的文章也会越来越有价值。重复，无论你面临什么困惑，总会有很多人同样面临过，于是你苦苦思索之后的结果，肯定会对很多人有意义。&lt;br /&gt;&lt;br /&gt;或者，你想通了之后觉得其实也很简单于是不愿意或者不好意思写了，但要知道，问题在想通了之后总是简单的，问题的困难程度不在于想通了之后还觉得有多难，而在于从你觉得它难到你觉得它简单需要耗费多少思维体力，你耗费的时间越长，说明有越多的人最终还是没有想明白（路越长走到底的人越少）。&lt;br /&gt;&lt;br /&gt;最后，虽然我现在看一年前的文章觉得挺不成熟，但是如果没有那些不成熟的思考，也不会有现在更成熟的思考，我几年后来看现在写的东西，还是会觉得不成熟。&lt;br /&gt;&lt;br /&gt;2) 担心想法太幼稚或有漏洞等等被别人笑话。人非圣贤。正是因为单个人的想法总是有漏洞，才值得拿出来交流（《书写是更好的思考》，讨论是绝佳的反思），被别人指出问题正是改进的空间，藏着掖着的想法永远不可能变得更成熟。&lt;br /&gt;&lt;br /&gt;Much of intelligence is knowledge，有这么一个非常发人深省的经典心理学实验[4]：&lt;br /&gt;&lt;br /&gt;将孩子们分成两组，通过给他们不同的阅读材料让一组相信智力是天生的，不可在后天改变的，另一组则让他们相信智力其实只是知识和技能的代名词，完全是后天习得的。接下来让他们做一组任务，那些被相信智力天生说的孩子，倾向于回避困难的任务，选择较容易的任务，这里的逻辑想必是这样的：如果做困难的任务，就增大了失败的几率，就在降低了自己在别人和自己心目中的智力的值。为了保护这个智力的值不被降低，应该避免那些有失败风险的项目。而另一组孩子则对于有挑战性的事情跃跃欲试，并且在失败的时候明显没有前者沮丧，因为失败也是学得新的东西，不管怎样都是“智力”的提高。&lt;br /&gt;&lt;br /&gt;况且，只会批判乃至嘲笑别人的人是最不知道怎么建设的人，忽略他们。&lt;br /&gt;&lt;br /&gt;3) 得不到激励。这其实是个最无聊的问题了，只有写碎碎念的博客才会面对“激励”的问题。如果写自己的总结，写自己独立的思考，那么书写下来、理解通透，本身就是一个极大的激励。就算放在自己的私密笔记本里面也一样有成就感。况且，如果你真做到了书写价值博客，那么绝对不用担心你的观点得不到传播，也许一开始会耗时长一点，但是这在任何事情上都是必要的初始阶段，Gmail小组的核心人物、FriendFeed创始人Paul Buchheit，和编程界名博Coding Horror的博主Jeff Atwood都曾经感叹过：Overnight success takes a long time （(1)，(2)），不过对于价值博客来说，现在网络上的聚合类服务这么多，机器的、人肉的、半人肉的都有，情况又要好得多了，而且我相信情况还会越来越好。&lt;br /&gt;&lt;br /&gt;4) 写不出来。这个问题也比较无聊，思考本不是一件急于求成的事情。长期订阅我的博客的朋友知道我一般发文频率在一个月三五篇，实际上有不少次我个把月也不发布文章，原因很简单，要么是有手头的事情要处理思考的时间被压缩了，要么是遇到比较大或者比较困难的问题需要长时间的思考和积淀，没有关系，如果没有想清楚就再想想，爱思考的人和不爱思考的人有一个本质的区别，前者在生活中总是挂着几个问题在大脑中，它们时常都会冒出来骚扰你一下，让你琢磨琢磨，不爱思考的则是没事不主动想问题，遇到问题还要先想想是否能找捷径（找人帮忙）解决。&lt;br /&gt;&lt;br /&gt;无论如何，不用急于求成，在一个主题上深入下去思考，总能挖到别人挖不到的角落。你能让一个问题在大脑中停留的时间越长，就越是能够发现新的东西，一般来说，我认为有价值的问题我会让他在意识或潜意识中待短则一个星期，长则一个月（视问题大小而定），利用走路吃饭的时间琢磨（我发现很多我佩服的人也都有这个习惯），有时即便已经想通了写下来了发出去了，大脑仍然还是会在回味问题，还没有把它撤出潜意识，然后看到某篇文章或某本书的时候忽然又有所新的感悟。&lt;br /&gt;&lt;br /&gt;能够把问题长时间停靠在潜意识中是一种技能，能够带来很大的好处，停留得越长你越琢磨得透彻，比别人看到的就越多。我们必须要带着问题的眼镜看待事物才能发现新的视角，否则就会出现视而不见效应，别的不说，广为人知的例子是阿基米德的“尤里卡！”，如果不是长时间琢磨着一个问题，一直把它放在思维中，是不会从洗澡领悟到“排水测体积”的，否则他洗了那么多年澡怎么不早发现呢？[5]&lt;br /&gt;&lt;br /&gt;所以，如果你习惯了思考问题，就总会有东西写，先有思考，然后有总结，然后在总结中进一步思考。&lt;br /&gt;&lt;br /&gt;当然你也可以试试把不成熟的想法写下来，试图整理成条理清晰的文字，然后看看能否在整理的过程中走得更远。这往往是可行的。比如这篇文章在我的简记里面原本其实只有三行字（包含大约十来个备忘关键词），而最初在我的大脑里面其实只有一个走路时冒出来的问题——为什么要写博客？&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;&lt;br /&gt;[1] 你可以看一下我收藏的一些精彩主题。&lt;br /&gt;&lt;br /&gt;[2] 尽管我并不完全同意这句话本身，但它这种解决问题链上更基本环节的问题的精神是我赞同的。&lt;br /&gt;&lt;br /&gt;[3] 《影响力2》这个名字起得很聪明，其实它并不是《影响力》的作者写的。&lt;br /&gt;&lt;br /&gt;[4] 我忘了这则实验的出处了，但实验的精神是记忆犹新的，哪位同学记得原始出处的麻烦提醒我一下。&lt;br /&gt;&lt;br /&gt;[5] 对于阿基米德这个故事的真实性是有争议的，毕竟几千年久远的事情谁弄得清呢。但是故事的道理是很本质的，我们平时也经常有类似的体验，加上阿基米德的“尤里卡”实在太出名了，所以我相信用用无妨。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-7090507157248689172?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/7090507157248689172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/7090507157248689172'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2009/01/why-i-maintian-such-blog.html' title='Why I maintian such a blog'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-4743368409392254689</id><published>2008-06-01T23:50:00.000-07:00</published><updated>2008-06-01T23:50:00.779-07:00</updated><title type='text'>砂之迷图</title><content type='html'>生まれた日から人は旅して&lt;br /&gt;遥かな星をいくつ数える&lt;br /&gt;无限のきらめきは夜空の嗫き&lt;br /&gt;迷い惑わされて风がさらつていく&lt;br /&gt;ああ连命数える星に导かれ&lt;br /&gt;ああ心の迷图をさまよい绕ける&lt;br /&gt;梦の旅人&lt;br /&gt;&lt;br /&gt;地平の果てに人影追つて&lt;br /&gt;アシスの町探してみても&lt;br /&gt;かすかな想い出が描く蜃气楼&lt;br /&gt;迷い惑わされて砂がさらつていく&lt;br /&gt;ああ连命变えてく流砂にまかれて&lt;br /&gt;ああ心の迷图をさまよい绕ける&lt;br /&gt;梦の旅人&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;かすかな想い出が描く蜃气楼&lt;br /&gt;迷い惑わされて砂がさらつていく&lt;br /&gt;ああ连命数える星に导かれ&lt;br /&gt;ああ心の迷图をさまよい绕ける&lt;br /&gt;梦の旅人&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-4743368409392254689?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/4743368409392254689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/4743368409392254689'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2008/06/blog-post.html' title='砂之迷图'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-5895976217135797684</id><published>2008-01-01T03:40:00.000-08:00</published><updated>2008-01-06T03:42:05.614-08:00</updated><title type='text'>和子由渑池怀旧</title><content type='html'>人生到处知何似，&lt;br /&gt;应似飞鸿踏雪泥。&lt;br /&gt;泥上偶然留指爪，&lt;br /&gt;鸿飞那复计东西。&lt;br /&gt;老僧已死成新塔，&lt;br /&gt;坏壁无由见旧题。&lt;br /&gt;往日崎岖还记否，&lt;br /&gt;路长人困蹇驴嘶。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-5895976217135797684?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/5895976217135797684'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/5895976217135797684'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2008/01/blog-post.html' title='和子由渑池怀旧'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-4233770142931174113</id><published>2007-12-31T03:44:00.000-08:00</published><updated>2008-01-06T03:47:34.401-08:00</updated><title type='text'>Category of TeleStar's Notes in 2007</title><content type='html'>&lt;ul&gt;&lt;li&gt;January - Quantum Related &lt;/li&gt;&lt;li&gt;February - &lt;/li&gt;&lt;li&gt;March - &lt;/li&gt;&lt;li&gt;April - &lt;/li&gt;&lt;li&gt;May - &lt;/li&gt;&lt;li&gt;June - &lt;/li&gt;&lt;li&gt;July - &lt;/li&gt;&lt;li&gt;August - &lt;/li&gt;&lt;li&gt;September - &lt;/li&gt;&lt;li&gt;Octobor - &lt;/li&gt;&lt;li&gt;November - &lt;/li&gt;&lt;li&gt;December - &lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-4233770142931174113?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/4233770142931174113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/4233770142931174113'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2007/12/category-of-telestars-notes-in-2007.html' title='Category of TeleStar&apos;s Notes in 2007'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-6546742334772296601</id><published>2007-05-01T23:35:00.000-07:00</published><updated>2009-04-15T07:25:09.049-07:00</updated><title type='text'>约翰·克里斯朵夫 （节选）</title><content type='html'>　　圣者克利斯朵夫渡过了河。他在逆流中走了整整的一夜。现在他结实的身体象一块&lt;br /&gt;岩石一般矗立在水面上，左肩上扛着一个娇弱而沉重的孩子。圣者克利斯朵夫倚在一株&lt;br /&gt;拔起的松树上；松树屈曲了，他的脊骨也屈曲了。那些看着他出发的人都说他渡不过&lt;br /&gt;的。他们长时间的嘲弄他，笑他。随后，黑夜来了。他们厌倦了。此刻克利斯朵夫已经&lt;br /&gt;走得那么远，再也听不见留在岸上的人的叫喊。在激流澎湃中，他只听见孩子的平静的&lt;br /&gt;声音，——他用小手抓着巨人额上的一绺头发，嘴里老喊着："走罢！"——他便走着，&lt;br /&gt;伛着背，眼睛向着前面，老望着黑洞洞的对岸，峭壁慢慢的显出白色来了。&lt;br /&gt;&lt;br /&gt;　　早祷的钟声突然响了，无数的钟声一下子都惊醒了。天又黎明！黑沉沉的危崖后&lt;br /&gt;面，看不见的太阳在金色的天空升起。快要倒下来的克利斯朵夫终于到了彼岸。于是他&lt;br /&gt;对孩子说：&lt;br /&gt;&lt;br /&gt;　　"咱们到了！唉，你多重啊！孩子，你究竟是谁呢？"&lt;br /&gt;&lt;br /&gt;　　孩子回答说：&lt;br /&gt;&lt;br /&gt;　　"我是即将来到的日子。"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-6546742334772296601?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/6546742334772296601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/6546742334772296601'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2007/05/blog-post.html' title='约翰·克里斯朵夫 （节选）'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-28049370713743777</id><published>2007-02-21T04:38:00.000-08:00</published><updated>2007-04-13T04:44:45.375-07:00</updated><title type='text'>いい日旅立ち</title><content type='html'>雪解け間近の　北の空に向かい&lt;br /&gt;過ぎ去りし日々の夢をさけぶとき&lt;br /&gt;帰らぬ人たち　熱い胸を過ぎる&lt;br /&gt;せめて今日から一人きり　旅に出る&lt;br /&gt;ああ　日本のどこかに&lt;br /&gt;わたしを待ってる人がいる&lt;br /&gt;いい日旅立ち　夕焼けを探しに&lt;br /&gt;母の背中で聞いた歌を道連れに&lt;br /&gt;&lt;br /&gt;岬のは外(ず)れに 少年は魚釣り&lt;br /&gt;あおいすすきの小道を 帰るのか&lt;br /&gt;わたしは今から思い出をつ作るため&lt;br /&gt;砂に枯れ木で書くつもり　さよならと&lt;br /&gt;ああ　日本のどこかに&lt;br /&gt;わたしを待ってる人がいる&lt;br /&gt;いい日旅だち　羊雲を探しに&lt;br /&gt;父が教えてくれた歌を道連れに&lt;br /&gt;&lt;br /&gt;ああ　日本のどこかに&lt;br /&gt;わたしを待ってる人がいる&lt;br /&gt;いい日旅だち　幸せを探しに&lt;br /&gt;子供のころに歌った歌を道連れに&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-28049370713743777?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/28049370713743777'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/28049370713743777'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2007/02/blog-post.html' title='いい日旅立ち'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-8690579809448289731</id><published>2007-01-29T20:09:00.000-08:00</published><updated>2009-02-08T20:10:29.658-08:00</updated><title type='text'>Resolving Vacuum Fluctuations in an Electrical Circuit by Measuring the Lamb Shift</title><content type='html'>道穷则反，归乎坤元。呵呵&lt;br /&gt;&lt;br /&gt;from http://www.sciencemag.org/cgi/content/full/322/5906/1357&lt;br /&gt;&lt;br /&gt;Quantum theory predicts that empty space is not truly empty. Even in the absence of any particles or radiation, in pure vacuum, virtual particles are constantly created and annihilated. In an electromagnetic field, the presence of virtual photons manifests itself as a small renormalization of the energy of a quantum system, known as the Lamb shift. We present an experimental observation of the Lamb shift in a solid-state system. The strong dispersive coupling of a superconducting electronic circuit acting as a quantum bit (qubit) to the vacuum field in a transmission-line resonator leads to measurable Lamb shifts of up to 1.4% of the qubit transition frequency. The qubit is also observed to couple more strongly to the vacuum field than to a single photon inside the cavity, an effect that is explained by taking into account the limited anharmonicity of the higher excited qubit states.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-8690579809448289731?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/8690579809448289731'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/8690579809448289731'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2009/02/blog-post.html' title='Resolving Vacuum Fluctuations in an Electrical Circuit by Measuring the Lamb Shift'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-7388176424016082954</id><published>2007-01-28T05:36:00.000-08:00</published><updated>2007-09-13T20:49:05.512-07:00</updated><title type='text'>Some websites for Quantum Computation</title><content type='html'>1.&lt;br /&gt;Berkeley CS294 Quantum Computation&lt;br /&gt;http://www.cs.berkeley.edu/~vazirani/quantum.html&lt;br /&gt;&lt;br /&gt;To believe it or not, this is a 2XX course, so I think it is for undergraduate students&lt;br /&gt;&lt;br /&gt;2.&lt;br /&gt;Q-circuit is a macro package for drawing quantum circuit diagrams in LaTeX. On this page you'll find everything you need to start making quantum circuit diagrams of your own.&lt;br /&gt;http://info.phys.unm.edu/Qcircuit/&lt;br /&gt;&lt;br /&gt;3.&lt;br /&gt;Professor Michael Nielsen Nielsen's blog&lt;br /&gt;http://www.qinfo.org/people/nielsen/blog/&lt;br /&gt;&lt;br /&gt;you will find so many links there&lt;br /&gt;&lt;br /&gt;4.&lt;br /&gt;The Cambridge QIP Website presents all QIP research that is currently active in Cambridge.&lt;br /&gt;http://www.qubit.org/&lt;br /&gt;&lt;br /&gt;5.&lt;br /&gt;Dave Bacon's blog&lt;br /&gt;http://dabacon.org/pontiff/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-7388176424016082954?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/7388176424016082954'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/7388176424016082954'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2007/01/some-websites-for-quantum-computation.html' title='Some websites for Quantum Computation'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-5985735930328103515</id><published>2007-01-11T23:06:00.000-08:00</published><updated>2007-03-07T23:22:52.296-08:00</updated><title type='text'>Some notes on D-Wave Orion</title><content type='html'>It seems that I by chance forecast the anouncement of D-wave this month. ^_^&lt;br /&gt;But to tell the truth, I really doubt how accurate D-wave behave like a true quantum machine. Below are some notes I found on the web. It is a pitty that I cannot connect to http://dwave.wordpress.com/ or http://www.scottaaronson.com/ (totally do not know why).&lt;br /&gt;&lt;br /&gt;1.&lt;br /&gt;   benleidawang (本垒打王) 于  (Sun Feb 18 19:06:17 2007)  提到:&lt;br /&gt;&lt;br /&gt;他们宣布的日子是2007年2月13日，可能是为了和世界上第一台电子计算机的发明放在一起。&lt;br /&gt;&lt;br /&gt;  1946年2月14日 世界上第一台计算机ENIAC诞生。也许在计算日期的时候有些不一致，他们选了2月13日。&lt;br /&gt;&lt;br /&gt;  实际上英国的巨人计算机（Giant）比美国的ENIVAC还要早，为了破译密码的保密需要，没有公布。&lt;br /&gt;&lt;br /&gt;nature上的报道&lt;br /&gt;http://www.nature.com/news/2007/070212/full/070212-8.html&lt;br /&gt;&lt;br /&gt;ZOL上的编译报道&lt;br /&gt;http://news.zol.com.cn/51/511468.html&lt;br /&gt;&lt;br /&gt;D-Wave的专利网页&lt;br /&gt;http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO2&amp;Sect2=HITOFF&amp;u=%2Fnetahtml%2FPTO%2Fsearch-adv.htm&amp;r=1&amp;p=1&amp;f=G&amp;l=50&amp;d=PTXT&amp;S1=7,135,701.PN.&amp;OS=PN/7,135,701&amp;RS=PN/7,135,701&lt;br /&gt;&lt;br /&gt;2.&lt;br /&gt;发信人: draculalord ( 嗯？), 信区: SF&lt;br /&gt;标  题: Re: 全球首台商用量子计算机将在下周展示 (转载)&lt;br /&gt;发信站: 水木社区 (Tue Feb 13 03:46:10 2007), 站内&lt;br /&gt;&lt;br /&gt;Grudgingly offered for your reading pleasure, and in the vain hope of forest&lt;br /&gt;alling further questions.&lt;br /&gt;&lt;br /&gt;Q: Thanks to D-Wave Systems — a startup company that’s been in the news la&lt;br /&gt;tely for its soon-to-be-unveiled “Orion” quantum computer — is humanity n&lt;br /&gt;ow on the verge of being able to solve NP-complete problems in polynomial ti&lt;br /&gt;me?&lt;br /&gt;&lt;br /&gt;A: No. We’re also not on the verge of being able to build perpetual-motion &lt;br /&gt;machines or travel faster than light.&lt;br /&gt;&lt;br /&gt;Q: But couldn’t quantum computers try all possible solutions in parallel, a&lt;br /&gt;nd thereby solve NP-complete problems in a heartbeat?&lt;br /&gt;&lt;br /&gt;A: Yes, if the heart in question was beating exponentially slowly.&lt;br /&gt;&lt;br /&gt;Otherwise, no. Contrary to widespread misconception, a quantum computer coul&lt;br /&gt;d not “try all possible solutions in parallel” in the sense most people me&lt;br /&gt;an by this. In particular, while quantum computers would apparently provide &lt;br /&gt;dramatic speedups for a few “structured” problems (such as factoring integ&lt;br /&gt;ers and simulating physical systems), it’s conjectured that they couldn’t &lt;br /&gt;solve NP-complete problems in polynomial time.&lt;br /&gt;&lt;br /&gt;Q: But isn’t factoring an NP-complete problem?&lt;br /&gt;&lt;br /&gt;A: Good heavens, no! While factoring is believed to be intractable for class&lt;br /&gt;ical computers, it’s not NP-complete, unless some exceedingly unlikely thin&lt;br /&gt;gs happen in complexity theory. Where did you get the idea that factoring wa&lt;br /&gt;s NP-complete? (Now I know how Richard Dawkins must feel when someone asks h&lt;br /&gt;im to explain, again, how “life could have arisen by chance.”)&lt;br /&gt;&lt;br /&gt;Q: How could the people at D-Wave not understand that quantum computers coul&lt;br /&gt;dn’t solve NP-complete problems in polynomial time?&lt;br /&gt;&lt;br /&gt;A: To his credit, Geordie Rose (the founder of D-Wave) does understand this;&lt;br /&gt; see here for example. And yet, essentially every article I’ve read about D&lt;br /&gt;-Wave gives readers exactly the opposite impression. The charitable explanat&lt;br /&gt;ion is that the D-Wave folks are being selectively quoted or misquoted by jo&lt;br /&gt;urnalists seeking to out-doofus one another. If so, one hopes that D-Wave wi&lt;br /&gt;ll try harder in the future to avoid misunderstandings.&lt;br /&gt;&lt;br /&gt;Q: But even if it gave only polynomial speedups (as opposed to exponential o&lt;br /&gt;nes), couldn’t the adiabatic quantum computer that D-Wave built still be us&lt;br /&gt;eful for industrial optimization problems?&lt;br /&gt;&lt;br /&gt;A: D-Wave’s current machine is said to have sixteen qubits. Even assuming i&lt;br /&gt;t worked perfectly, with no decoherence or error, a sixteen-qubit quantum co&lt;br /&gt;mputer would be about as useful for industrial optimization problems as a ro&lt;br /&gt;ast-beef sandwich.&lt;br /&gt;&lt;br /&gt;Q: But even if it wasn’t practically useful, wouldn’t a 16-qubit supercond&lt;br /&gt;ucting quantum computer still be a major scientific advance?&lt;br /&gt;&lt;br /&gt;A: Yes, absolutely.&lt;br /&gt;&lt;br /&gt;Q: So, can D-Wave be said to have achieved that goal?&lt;br /&gt;&lt;br /&gt;A: As Dave Bacon pointed out earlier, it’s impossible to answer that questi&lt;br /&gt;on without knowing more about how their machine works. With sixteen qubits, &lt;br /&gt;a “working demo” doesn’t prove anything. The real questions are: how high&lt;br /&gt; are the fidelities, and what are the prospects for scalability?&lt;br /&gt;&lt;br /&gt;Q: But clearly D-Wave isn’t going to give away its precious trade secrets j&lt;br /&gt;ust to satisfy some niggling academics! Short of providing technical specifi&lt;br /&gt;cs, what else could they do to make computer scientists take them seriously?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A: Produce the prime factors of&lt;br /&gt;&lt;br /&gt;1847699703211741474306835620200164403018549&lt;br /&gt;&lt;br /&gt;3386634101714717857749106516967111612498593&lt;br /&gt;&lt;br /&gt;3768430543574458561606154457179405222971773&lt;br /&gt;&lt;br /&gt;2524660960646946071249623720442022269756756&lt;br /&gt;&lt;br /&gt;6873784275623895087646784409332851574965788&lt;br /&gt;&lt;br /&gt;4341508847552829818672645133986336493190808&lt;br /&gt;&lt;br /&gt;4671990431874381283363502795470282653297802&lt;br /&gt;&lt;br /&gt;9349161558118810498449083195450098483937752&lt;br /&gt;&lt;br /&gt;2725705257859194499387007369575568843693381&lt;br /&gt;&lt;br /&gt;2779613089230392569695253261620823676490316&lt;br /&gt;&lt;br /&gt;036551371447913932347169566988069.&lt;br /&gt;&lt;br /&gt;Q: Alright, what else could they do?&lt;br /&gt;&lt;br /&gt;A: Avoid talking like this:&lt;br /&gt;&lt;br /&gt;The system we are currently deploying, which we call Trinity, is a capabilit&lt;br /&gt;y-class supercomputer specifically designed to provide extremely rapid and a&lt;br /&gt;ccurate approximate answers to arbitrarily large NP-complete problems … Tri&lt;br /&gt;nity has a front-end software interface, implemented in a combination of Jav&lt;br /&gt;a and C, that allows a user to easily state any NP-complete problem of inter&lt;br /&gt;est. After such a problem has been stated the problem is compiled down to th&lt;br /&gt;e machine language of the processors at the heart of the machine. These proc&lt;br /&gt;essors then provide an answer, which is shuttled back to the front end and p&lt;br /&gt;rovided to the user. This capability can of course be called remotely and/or&lt;br /&gt; as a subroutine of some other piece of software.&lt;br /&gt;&lt;br /&gt;Or to translate: “Not only have we built a spaceship capable of reaching Pl&lt;br /&gt;uto in a few hours, our spaceship also has tinted windows and deluxe leather&lt;br /&gt; seats!” If I were them, I’d focus more on the evidence for their core tec&lt;br /&gt;hnological claims, given that those claims are very much what’s at issue.&lt;br /&gt;&lt;br /&gt;Q: While Dave Bacon also expressed serious doubts about the Orion quantum co&lt;br /&gt;mputer, he seemed more enthusiastic than you are. Why?&lt;br /&gt;&lt;br /&gt;A: Generous and optimistic by nature, Dave strives to give others the benefi&lt;br /&gt;t of the doubt (as the Chinese restaurant placemat would put it). Furthermor&lt;br /&gt;e, as Quantum Pontiff, he’s professionally obligated to love the quantum si&lt;br /&gt;nner and forgive the wayward quantum sheep. And these are all wonderful qual&lt;br /&gt;ities to have. On the other hand, when the hype surrounding some topic cross&lt;br /&gt;es a certain threshold, arguably a pricklier approach becomes called for.&lt;br /&gt;&lt;br /&gt;Q: If D-Wave fizzles out, will many journalists and policymakers then conclu&lt;br /&gt;de that quantum computing is bunk?&lt;br /&gt;&lt;br /&gt;A: It doesn’t seem unlikely.&lt;br /&gt;&lt;br /&gt;Q: What would it take to get these people to recognize the most elementary d&lt;br /&gt;istinctions?&lt;br /&gt;&lt;br /&gt;A: That’s the question, isn’t it? &lt;br /&gt;&lt;br /&gt;This entry was posted on Friday, February 9th, 2007 at 9:34 am and is filed &lt;br /&gt;under Quantum, Rage Against Doofosity. You can follow any responses to this &lt;br /&gt;entry through the RSS 2.0 feed. You can leave a response, or trackback from &lt;br /&gt;your own site. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;※ 来源:·水木社区 newsmth.net·[FROM: 147.83.49.*]&lt;br /&gt;&lt;br /&gt;3.&lt;br /&gt;   Krank (娉娉袅袅十三馀，豆蔻梢头二月初) 于  (Sat Feb 17 20:31:07 2007)  提到:&lt;br /&gt;&lt;br /&gt;http://dwave.wordpress.com/2007/01/19/quantum-computing-demo-announcement/&lt;br /&gt;&lt;br /&gt;这里可以看到它们的芯片设计。&lt;br /&gt;&lt;br /&gt;事情有点没谱，D-WAVE现在干的这件事好像是好莱坞电影里面的情节。这个D-WAVE里&lt;br /&gt;有一批做FLUX QUBIT的人不假，包括一些从CLARKE那里去的，从MARTINIS那里去的，&lt;br /&gt;还有从UMD去的。嘿嘿，正因为如此，如果他们有什么决定性的突破，我这里绝对不会&lt;br /&gt;听不到风声。&lt;br /&gt;&lt;br /&gt;如果是“真实的”量子计算，16个固然了不起，不过我看了一下他们的方案，跟别的&lt;br /&gt;实验室做的方案相比没有本质上的突破。D-WAVE虽然牛，也还没牛到让全世界的同行&lt;br /&gt;都瞠若乎后的地步。他们这个方案也没有公开发表的文章（当然是商业机密），也不&lt;br /&gt;知道具体的纠缠方式和退相干时间。&lt;br /&gt;&lt;br /&gt;总之我觉得这个事情更像是“炒概念”，也许是商业操作吧。简单地一语道破，这里&lt;br /&gt;所谓16个QBIT的纠缠态，事实上并没有完全的纠缠。D-WAVE搞的小把戏其实自己也说&lt;br /&gt;得很清楚，这是类似于2D的ISING模型的纠缠，所谓纠缠只存在于相邻的BIT中。他们&lt;br /&gt;的4X4的阵列就表示16个纠缠QUBIT么？这至少相当于2D的ISING模型和2D的自由电子气&lt;br /&gt;的区别吧。&lt;br /&gt;&lt;br /&gt;不过他们炒概念也不错，反正把蛋糕做大，我们这帮人谁都有好处。但是也正像NATURE&lt;br /&gt;新闻里面说的，这样炒概念是玩火，如果把概念炒臭了，害处很大，成为跟高温超导&lt;br /&gt;一样人见人怕的资金毒药……&lt;br /&gt;&lt;br /&gt;4.&lt;br /&gt;   Krank (娉娉袅袅十三馀，豆蔻梢头二月初) 于  (Mon Feb 19 00:55:16 2007)  提到:&lt;br /&gt;&lt;br /&gt;看来跟我持同样观点的同行还是不少的。&lt;br /&gt;&lt;br /&gt;Real Deal? &lt;br /&gt;&lt;br /&gt;Because Orion must be kept refrigerated and isolated from outside influences&lt;br /&gt; that could disrupt its computations, the company only remotely accessed the&lt;br /&gt; system in its demonstration. Likewise, D-Wave hasn't proven Orion's exact n&lt;br /&gt;ature to the scientific community, but may release details for scientific pe&lt;br /&gt;er review. At that point, scientists can argue over the finer points of quan&lt;br /&gt;tum mechanics and if Orion is truly a "quantum computer."&lt;br /&gt;&lt;br /&gt;http://www.technewsworld.com/story/55801.html&lt;br /&gt;&lt;br /&gt; Krank (娉娉袅袅十三馀，豆蔻梢头二月初) 于  (Mon Feb 19 01:01:05 2007)  提到:&lt;br /&gt;&lt;br /&gt;呵呵，这个更搞笑，D-WAVE的人自己承认是耍花招了。&lt;br /&gt;&lt;br /&gt;And notwithstanding lofty claims in the company's press release about creati&lt;br /&gt;ng the world's first commercial quantum computer, D-Wave Chief Executive Her&lt;br /&gt;b Martin emphasized that the machine is not a true quantum computer and is i&lt;br /&gt;nstead a kind of special-purpose machine that uses some quantum mechanics to&lt;br /&gt; solve problems.&lt;br /&gt;&lt;br /&gt;~~~~这种手段太不道德了，恩恩，赤裸裸的商业行为！&lt;br /&gt;&lt;br /&gt;"Users don't care about quantum computing - users care about application acc&lt;br /&gt;eleration. That's our thrust," he said. "A general purpose quantum computer &lt;br /&gt;is a waste of time. You could spend hundreds of billions of dollars on it" a&lt;br /&gt;nd not create a working computer.&lt;br /&gt;&lt;br /&gt;He said all the evidence the company has indicates that the device is perfor&lt;br /&gt;ming quantum computations, but he acknowledged there is some uncertainty. He&lt;br /&gt; also said the company could encounter problems in maintaining quantum funct&lt;br /&gt;ions as the machine is made more powerful.&lt;br /&gt;&lt;br /&gt;http://www.ibtimes.com/articles/20070214/techbit-quantum-quandary.htm&lt;br /&gt;&lt;br /&gt;Krank (娉娉袅袅十三馀，豆蔻梢头二月初) 于  (Mon Feb 19 20:40:42 2007)  提到:&lt;br /&gt;&lt;br /&gt;其实这个东西本身还是挺好的，基本上相当于一个宏观的二维ISING模型。能做出&lt;br /&gt;这个东西相当于用宏观物体直接对微观过程进行量子模拟，或者说量子复现。这个&lt;br /&gt;门槛可是相当得不低啊，至少全世界我数不出10个实验室能做到。&lt;br /&gt;&lt;br /&gt;但是吹成16QBIT就是挑战整个研究领域了，未免口气大了些。如果在业内受到强烈&lt;br /&gt;反弹，对于D-WAVE企事业不是什么好事。正好我们这里后天就要开一个小会，欧洲&lt;br /&gt;所有超导量子计算的牛人基本上都会到，我到时候问问他们怎么看这个事情。&lt;br /&gt;&lt;br /&gt;benleidawang (本垒打王) 于  (Thu Feb 22 21:54:30 2007)  提到:&lt;br /&gt;&lt;br /&gt;Nature 今天的报道&lt;br /&gt;&lt;br /&gt;http://www.nature.com/nature/journal/v445/n7130/full/445807a.html&lt;br /&gt;&lt;br /&gt;Puzzle-solving quantum computer is unveiled&lt;br /&gt;A Canadian firm has revealed what it claims is the first fully functioning quantum computer — generating both interest and scepticism from physicists.&lt;br /&gt;&lt;br /&gt;D-Wave Systems, based in Burnaby, British Columbia, debuted its system on 13 February at the Computer History Museum in Mountain View, California. The computer used its 16 quantum bits, or qubits, to match proteins in a database, create a seating chart for a wedding party and solve a sudoku puzzle.&lt;br /&gt;&lt;br /&gt;Critics say that the machine, which takes an unusual approach known as 'adiabatic quantum computing', may not be performing strictly quantum-mechanical computations. The adiabitic technique leaves the machine to conduct quantum computations on its own, making it difficult to tell whether it is behaving in a quantum or a classical manner.&lt;br /&gt;&lt;br /&gt;"I'm really very sceptical," says Umesh Vazirani, a computer scientist at the University of California, Berkeley, adding that he would like to see more data before he is convinced.&lt;br /&gt;&lt;br /&gt;benleidawang (本垒打王) 于  (Thu Feb 22 22:00:28 2007)  提到:&lt;br /&gt;&lt;br /&gt;Physics Today Favorite 上转的报道&lt;br /&gt;&lt;br /&gt;The Father of Quantum Computing&lt;br /&gt;不知道是指D-Wave是量子计算机之父，还是指Deutsch是量子计算机之父&lt;br /&gt;http://blogs.physicstoday.org/newspicks/2007/02/the_father_of_quantum_computin.html&lt;br /&gt;&lt;br /&gt;Does quantum computing have a future?&lt;br /&gt;&lt;br /&gt;On Tuesday, Canadian company D-Wave Systems demonstrated a 16-qubit, specific-purpose quantum computer to a room packed with observers and thick with doubt and awe. Reporters watched as the machine solved a Sudoku puzzle and a seating arrangements problem, and, most impressively, searched for molecules similar to the drug Prilosec from a database of molecules.&lt;br /&gt;&lt;br /&gt;But the final significance of D-Wave's demo is as uncertain as the fate of Schr&amp;ouml;dinger's cat -- opinions are all over the place, within the scientific community and without. To cut through the fog, Wired News sought out the father of quantum computing, Oxford University theoretical physicist David Deutsch.&lt;br /&gt;&lt;br /&gt;Deutsch invented the idea of the quantum computer in the 1970s as a way to experimentally test the "Many Universes Theory" of quantum physics -- the idea that when a particle changes, it changes into all possible forms, across multiple universes.&lt;br /&gt;&lt;br /&gt;Deutsch is a leading proponent of the theory, so, while he wasn't in attendance at the D-Wave announcement, perhaps it's safe to say as well that he was. Wired News pulled him away from dinner to talk about what a quantum computer really is, what it's good for and what D-Wave's announcement might mean for the future.&lt;br /&gt;&lt;br /&gt;Wired News: D-Wave announced 16 qubits, and they want people to play with them, so they're talking about having a web API where people can try to port their own applications and see how it works. Do you think that's a good approach to gaining some acceptability and mind share for the idea of quantum computing?&lt;br /&gt;&lt;br /&gt;David Deutsch: I think the field doesn't need acceptability. The idea will either be valid, or not. The claim will either be true, or not. I think that the normal processes of scientific criticism, peer review and just general discussion in the scientific community is going to test this idea -- provided enough information is given of what this idea is. That will be quite independent of what kind of access they provide to the public.&lt;br /&gt;&lt;br /&gt;However, I think the idea of providing an interface such as you describe is a very good one. I think it's a wonderful idea....&lt;br /&gt;&lt;br /&gt;WN: Can you give a couple of examples of what kind of things can be done with quantum computing that either can't be done, or can't be done practically, with classical computing?&lt;br /&gt;&lt;br /&gt;Deutsch: The most important application of quantum computing in the future is likely to be a computer simulation of quantum systems, because that's an application where we know for sure that quantum systems in general cannot be efficiently simulated on a classical computer. This is an application where the quantum computer is ideally suited.&lt;br /&gt;&lt;br /&gt;Perhaps in the long run, as nanotechnology becomes quantum technology, that will be a very important generic application.&lt;br /&gt;&lt;br /&gt;Another thing I should say is, that application is the only one of the major applications -- apart from quantum cryptography, by the way, which is already implemented and is really in a different category -- that might be amenable to a non-general purpose quantum computer. That is to say, a special-purpose quantum computer.&lt;br /&gt;&lt;br /&gt;WN: Can you talk a little about the importance of simulating quantum systems, and give an example?&lt;br /&gt;&lt;br /&gt;Deutsch: Yes. Whenever we design a complex piece of technology we need to simulate it, either in theory by working out the equations that govern it, or as a computer simulation, by running a program on the computer whose motion mimics that of the real system.&lt;br /&gt;&lt;br /&gt;But when we come to designing quantum systems, we're going to have to simulate the behavior of quantum super positions, which is, in Many Universes terms, when an object is doing different things in different universes. On a classical computer you'd have to work out what every single one of those was, and then combine them in the end with the equations governing quantum interference.&lt;br /&gt;&lt;br /&gt;WN: And that becomes computationally impossible?&lt;br /&gt;&lt;br /&gt;Deutsch: That becomes infeasible very, very quickly, once you've got more than three, four, five particles involved, whereas a quantum computer could mimic such a process directly by itself doing that number of computations simultaneously in different universes. So it is naturally adapted to that kind of simulation, if we wanted to work out, let's say, the exactly properties of a given molecule.&lt;br /&gt;&lt;br /&gt;Some people have suggested this might be useful for designing new drugs, but we don't know if that's the case or not. Although quantum processes are needed in general for atomic and molecular scale properties, not all of them (need quantum processes). An example of that is we've been able to do a lot of biotechnology without having any quantum simulators.&lt;br /&gt;&lt;br /&gt;WN: Do you think a quantum computer could eventually build a slightly more macro simulation, something like an immune system, in order to see how it interacts with a drug?&lt;br /&gt;&lt;br /&gt;Deutsch: No, that's not what it would be used for. It would be used for smaller things, not things on a larger scale than a molecule, but things on a smaller scale. Small molecules and interactions within an atom, subtle differences between different isotopes, that sort of thing. And of course things on an even smaller scale than that. Nuclear physics, and also artificial, atomic-sized things which will be used in nanotechnology.&lt;br /&gt;&lt;br /&gt;Of which at the moment the only ones planned are quantum computers. Of course quantum computer designing other quantum computers is undoubtedly going to be one of the applications.&lt;br /&gt;&lt;br /&gt;WN: The other field I can see ... this revolutionizing is materials science.&lt;br /&gt;&lt;br /&gt;Deutsch: Yes, yes. Again we don't know how revolutionary it will be, but certainly on the small scale, it will be indispensable.&lt;br /&gt;&lt;br /&gt;WN: What would you like to see the field trying to do?&lt;br /&gt;&lt;br /&gt;Deutsch: I'm probably the wrong person to ask that because my own interest in this field is not really technological. To me quantum computation is a new and deeper and better way to understand the laws of physics, and hence understanding physical reality as a whole. We are really only scratching the surface of what it is telling us about the nature of the laws of physics. That's the kind of direction that I'm pursuing.&lt;br /&gt;&lt;br /&gt;The pleasant thing about that is that can be done before one even makes a quantum computer. The theoretical conclusions are already there, and we can work on them already. It's not that I don't think technological applications are important, but I watch them as an eager spectator rather than participant.&lt;br /&gt;&lt;br /&gt;WN: For your purposes, the importance of quantum computing is in the general case more than in the specific-use case.&lt;br /&gt;&lt;br /&gt;Deutsch: Yes. The fact that the laws of physics permit themselves to be simulated by a quantum computer is a deep fact about the nature of the universe that we will have to understand more deeply in the future.&lt;br /&gt;&lt;br /&gt;WN: How do you think using quantum computers will change how people think about computing, and consequently the universe and nature?&lt;br /&gt;&lt;br /&gt;Deutsch: "How they will think about it" is the relevant phrase here. This is a philosophical and psychological question you're asking. You're not asking a question about the physics or the logic of the situation.&lt;br /&gt;&lt;br /&gt;I think that when universal quantum computers are finally achieved technologically, and when they are routinely performing computations where there is simply more going on there than a classical computer or even the whole universe acting as a computer could possibly achieve, then people will get very impatient and bored, I think, with attempts to say that those computations don't really happen, and that the equations of quantum mechanics are merely ways of expressing what the answer would be but not how it was obtained.&lt;br /&gt;&lt;br /&gt;The programmers will know perfectly well how it was obtained, and they will have programmed the steps that will have obtained it. The fact that answers are obtained from a quantum computer that couldn't be obtained any other way will make people take seriously that the process that obtained them was objectively real.&lt;br /&gt;&lt;br /&gt;Nothing more than that is needed to lead to the conclusion that there are parallel universes, because that is specifically how quantum computers work.&lt;br /&gt;&lt;br /&gt;WN: So what prompted you to start thinking about quantum computing?&lt;br /&gt;&lt;br /&gt;Deutsch: This goes back a long way before I even thought of general purpose quantum computing. I was thinking about the relationship between computing and physics.... This was back in the 1970s....&lt;br /&gt;&lt;br /&gt;It had been said, ever since the parallel universes theory had been invented by Everett in the 1950s, that there's no experimental difference between it and the various (theories), like the Copenhagen interpretation, that try to deny that all but one of the universes exist.&lt;br /&gt;&lt;br /&gt;Although it had been taken for granted that there was no experimental difference, in fact, there is -- provided the observer can be analyzed as part of the quantum system. But you can only do that if the observer is implemented on quantum hardware, so I postulated this quantum hardware that was running an artificial intelligence program, and as a result was able to concoct an experiment which would give one output from an observer's point of view if the parallel universes theory was true, and a different outcome if only a single universe existed.&lt;br /&gt;&lt;br /&gt;This device that I postulated is what we would now call a quantum computer, but because I wasn't particularly thinking about computers, I didn't call it that, and I didn't really start thinking about quantum computation as a process until several years later. That lead to my suggesting the universal quantum computer and proving its properties in the mid-'80s.&lt;br /&gt;&lt;br /&gt;WN: How many qubits (does it take) to make the general-purpose quantum computer useful?&lt;br /&gt;&lt;br /&gt;Deutsch: I think the watershed moment with quantum computer technology will be when a quantum computer -- a universal quantum computer -- exceeds about 100 to 200 qubits.&lt;br /&gt;&lt;br /&gt;Now when I say qubits, I have to stress that the term qubit hasn't got a very precise definition at the moment, and I've been arguing for a long time that the physics community ought to get together and decide on some criteria for different senses for the word qubit. What I mean here is a qubit which is capable of being in any quantum state, and is capable of undergoing any kind of entanglement with another qubit of the same technology, and all those conditions are actually necessary to make a fully fledged quantum computer.&lt;br /&gt;&lt;br /&gt;If you relax any one of the those conditions it's much easier to implement in physics. For instance, if you call something a qubit but it can only be entangled with qubits of a different technology, then it's much easier to build. But of course a thing like that can't be made part of a computer memory. (With) computer memory you need lots of identical ones.&lt;br /&gt;&lt;br /&gt;There's also the question of error correction. The one physical qubit is probably not enough to act as a qubit in genuine quantum computation, because of the problem of errors and decoherence. So you need to implement quantum error correction, and quantum error correction is going to require several physical qubits for every logical qubit of the computer. When I said you need 100 to 200, that probably means several hundred, or perhaps 1,000 or more, physical qubits.&lt;br /&gt;&lt;br /&gt;WN: To get an effective 100 or 200 qubits.&lt;br /&gt;&lt;br /&gt;Deutsch: Yes, and that is what would have to count as the watershed for quantum computation, for being a distinctive new technology with its own genuine uses.&lt;br /&gt;&lt;br /&gt;WN: That's actually D-Wave's stated goal as well: essentially 1,000 qubits in two years. Do you think engineering-wise, and this is not completely within your realm, they will be able to maintain enough coherence at that level to create a practical computer.&lt;br /&gt;&lt;br /&gt;Deutsch: As you said that really isn't my field. Maintaining coherence itself isn't quite enough. They've got to maintain coherence in the operation that I spoke of; that is, the arbitrary superposition, the arbitrary entanglement, and so on....&lt;br /&gt;&lt;br /&gt;I don't know. The technologies I've seen so far have got way fewer than 1,000. They've got way fewer than 16. I always have to ask whether the claimed number of qubits are qubits that I would count as qubits by these stringent criteria, or whether it's merely two-state systems that can in some sense act in a quantum way. Because that's a much more lenient criterion.&lt;br /&gt;&lt;br /&gt;WN: I don't have the sophistication to answer that, for D-Wave at least. If I were to ask you to cast your mind forward, saying everything goes well, what does a world that combines ubiquitous quantum computing and classical computing look like? And you've said that quantum computing would never replace classical computing.&lt;br /&gt;&lt;br /&gt;Deutsch: It's not anywhere near as big a revolution as, say, the internet, or the introduction of computers in the first place. The practical application, from a ordinary consumer's point of view, are just quantitative.&lt;br /&gt;&lt;br /&gt;One field that will be revolutionized is cryptography. All, or nearly all, existing cryptographic systems will be rendered insecure, and even retrospectively insecure, in that messages sent today, if somebody keeps them, will be possible to decipher ... with a quantum computer as soon as one is built.&lt;br /&gt;&lt;br /&gt;Most fields won't be revolutionized in that way.&lt;br /&gt;&lt;br /&gt;Fortunately, the already existing technology of quantum cryptography is not only more secure than any existing classical system, but it's invulnerable to attack by a quantum computer. Anyone who cares sufficiently much about security ought to be instituting quantum cryptography wherever it's technically feasible.&lt;br /&gt;&lt;br /&gt;Apart from that, as I said, mathematical operations will become easier. Algorithmic search is the most important one, I think. Computers will become a little bit faster, especially in certain applications. Simulating quantum systems will become important because quantum technology will become important generally, in the form of nanotechnology.&lt;br /&gt;&lt;br /&gt;WN: If we have practical nanotechnology, I imagine that's a huge change.&lt;br /&gt;&lt;br /&gt;Deutsch: Nanotechnology has the potential of making a huge change. But the only involvement of quantum computers is that it will make it easier to design nanotechnological devices. Apart from that I don't think it's a big technological revolution.&lt;br /&gt;&lt;br /&gt;What it is though, philosophically, is taking a quantum world view. That is rather a revolution, but that could happen today and the only reason it has been sluggish in happening is psychological, and maybe quantum computers will help with this psychological process. That's a very indirect phenomenon.&lt;br /&gt;&lt;br /&gt;WN: It does allow people to play with it, and they often get things better when they play with them.&lt;br /&gt;&lt;br /&gt;Deutsch: That's true.&lt;br /&gt;&lt;br /&gt;WN: I wanted to ask you to describe your book a bit.&lt;br /&gt;&lt;br /&gt;Deutsch: You'll remember I said for me the most important thing about quantum computation is the way it shows us the deep connections between physics on the one hand and computation on the other, which were previously suspected by only a few pioneers like Rolf Landauer of IBM.&lt;br /&gt;&lt;br /&gt;My book (The Fabric of Reality) is about this connection between computation and fundamental physics, between those two apparently unconnected fields.... To me, (that connection is) part of a wider thing, where there are also two other strands, the theory of knowledge and the theory of evolution.&lt;br /&gt;&lt;br /&gt;The Fabric of Reality is my attempt to say that a world view formed out of those four strands is the deepest knowledge that we currently have about the world.&lt;br /&gt;&lt;br /&gt;benleidawang (本垒打王) 于  (Sat Feb 24 15:28:17 2007)  提到:&lt;br /&gt;&lt;br /&gt;在网上又查了一些东西。要点是：&lt;br /&gt;&lt;br /&gt;1.D-Wave在2005年就计划推出量子计算机雏型。里面有一点他们的技术解释。&lt;br /&gt;2.D-wave在2005年6月得到了1750万美元的风险投资。&lt;br /&gt; D-Wave Systems got $17.5 mln from Draper Fisher Jurvetson to work on a preliminary version of a quantum computer&lt;br /&gt;3.第3篇当时有关的评价；&lt;br /&gt;4.第4篇是说D-wave在2006年5月有了一个新的CEO Herbert J. Martin，有人对他的评价还不错。 &lt;br /&gt;&lt;br /&gt;-------------------------------------------------------------------------&lt;br /&gt;http://www.dgl.com/itinfo/weblog/archives/00000130.html&lt;br /&gt;Quantum Computer to be Ready in Three Years&lt;br /&gt;by Dave Murphy&lt;br /&gt;&lt;br /&gt;D-Wave Systems, a Vancouver-based computer engineering firm has announced it's schedule to build a working quantum computer that will be able to solve physical-simulation problems that currently aren't solvable using available processing tools. The computer is to be ready within three years. While most designs for quantum computers focus on the properties of quantum entanglement to calculate binary functions, the D-Wave system will use quantum tunneling, which enables particles to hop from one location to another without traversing the intervening space.&lt;br /&gt;&lt;br /&gt;D-Wave's design takes advantage of an low-temperature superconducting analog chip, rather than the sensitive lasers and vacuum tools required by other quantum computer designs.&lt;br /&gt;&lt;br /&gt;Dave's Opinion&lt;br /&gt;For those of you who are long-time ITrain subscribers, you know that I've had an interest in the development of quantum computing tools for more than two decades. I'm excited about D-Wave's design, and I have to admit, I'm heartened by the company's ability to break ranks and look to an alternative design that may facilitate the early adoption of quantum computing technology.&lt;br /&gt;&lt;br /&gt;Call for Comments&lt;br /&gt;What do you think? Leave your comments on the message center.&lt;br /&gt;&lt;br /&gt;References&lt;br /&gt;D-Wave Systems&lt;br /&gt;Message Center &lt;br /&gt;--------------------------------------------------------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A Working Quantum Computer in 3 Years? &lt;br /&gt;Posted by timothy on Wed Jun 22, '05 05:02 AM&lt;br /&gt;&lt;br /&gt;06.22.05 @ 03:50 PM ET &lt;br /&gt;author, 410.461.5366&lt;br /&gt;Copyright &amp;copy; 2005 Damar Group, Ltd., All Rights Reserved&lt;br /&gt;&lt;br /&gt;Vancouver, BC-based D-Wave Systems got $17.5 mln from Draper Fisher Jurvetson to work on a preliminary version of a quantum computer, Technology Review reports. Delivery date? Within three years: 'It won't be a fully functional quantum computer of the sort long envisioned; but D-Wave is on track to produce a special-purpose, "noisy" piece of quantum hardware that could solve many of the physical-simulation problems that stump today's computers, says David Meyer, a mathematician working on quantum algorithms at the University of California, San Diego.'"&lt;br /&gt;--------------------------------------------------------------------------------------------------------------------&lt;br /&gt;http://www.engadget.com/2005/06/23/d-wave-says-theyll-have-a-quantum-computer-ready-by-2008/&lt;br /&gt;D-Wave says they'll have a quantum computer ready by 2008&lt;br /&gt;Posted Jun 23rd 2005 11:42AM by Thomas Ricker&lt;br /&gt;Filed under: Misc. Gadgets&lt;br /&gt;&lt;br /&gt;If you think about it, a computer only needs to measure the change of state to, well, compute — be it ones and zeros or the state of subatomic particles. That's why there is such interest in the development of the mythical quantum computer (think supercomputer in a teaspoon). For the most part, efforts in quantum computer development have focused on a property called entanglement. But Vancouver startup D-Wave is focusing on quantum tunneling instead and hope to exploit this to develop a quantum computer within three-years (with a prototype by close of 2006). At the heart of their "less than fully functional" quantum computer is an analogue chip which must be cooled with liquid helium to -269 °C — just 4 °C shy of absolute zero folks! However, these purpose-built semiconductors rely on existing fabrication techniques and do not need the gee-whiz guts (delicate lasers, vacuum pumps) required by other quantum computers. While cryptographers will have to wait for their dream machine, intractable problems such as the infamous traveling-salesman (optimal route among cities) and optimization of financial portfolios and traditional computer chip layouts could be quickly sorted. Don't bother raiding the kid's college fund yet 'cause D-Wave expects to sell computational services not quantum hardware&lt;br /&gt;--------------------------------------------------------------------------------------------------------------------&lt;br /&gt;http://www.dabacon.org/pontiff/?p=1235&lt;br /&gt;D-Wave News&lt;br /&gt;May 9, 2006 on 6:27 pm | In Quantum, Computation | &lt;br /&gt;D-Wave Systems, those crazy Vancouverites trying to build a quantum computer, have a new CEO:&lt;br /&gt;VANCOUVER, BRITISH COLUMBIA, May 9 /CNW/ - D-Wave, developer of the world’s most advanced computers, has appointed Silicon Valley technology executive and entrepreneur Herbert J. Martin as chief executive officer. &lt;br /&gt;Which makes me dream of the day when I will be able to include in my grant proposal a request for dollars to buy a quantum computer. &lt;br /&gt;1.    It’s a good sign. Herb is a top caliber CEO. Someone with his experience, background and success rate wouldn’t join the company if the technology wasn’t already working. Building working machines is necessary but not sufficient to build a successful business. History is littered with cool technologies that have failed in the marketplace. &lt;br /&gt;Comment by Geordie — 5/12/2006&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-5985735930328103515?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/5985735930328103515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/5985735930328103515'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2007/01/some-notes-on-d-wave-orion.html' title='Some notes on D-Wave Orion'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-117005739175857064</id><published>2007-01-08T23:41:00.000-08:00</published><updated>2007-01-28T23:56:31.843-08:00</updated><title type='text'>Some notes on quantum communication - 1</title><content type='html'>1.&lt;br /&gt;http://eve.physics.ox.ac.uk/NewWeb/Research/communication/communication.html&lt;br /&gt;&lt;br /&gt;2.&lt;br /&gt;http://www.edn.com/article/CA6290450.html&lt;br /&gt;&lt;br /&gt;3.&lt;br /&gt;量子信息技术的新进展 &lt;br /&gt;&lt;br /&gt;——五光子纠缠和开放目的的量子隐形传态&lt;br /&gt;&lt;br /&gt;中国科学院院刊&lt;br /&gt;&lt;br /&gt;量子信息学主要是利用微观粒子作为载体，凭借着量子力学所特有的一些性质：不确定性、相干性、纠缠等，可以完成一些经典的通讯、计算、密码学无法实现的任务。包括，量子密钥分发具有绝对的安全性，量子计算机具有高并行性，因而在解决一些特定的复杂问题中具有经典计算机无法比拟的优势。量子隐形传态6，9可以通过量子纠缠和一个经典信道，完整无误地传送一个量子态，量子密集编码的信道容量是经典信道的两倍等。&lt;br /&gt;&lt;br /&gt;    量子纠缠可以说是量子信息最核心部分，几乎所有的量子信息处理过程都与其有关。量子纠缠本来是爱因斯坦等科学家为了证明量子力学的不完备而提出的一种很奇妙的量子概念，而在量子信息学中却成为最重要一种资源，并有着大量的应用：如在量子密钥分发中，基于量子纠缠交换和量子纠缠纯化的量子中继器可以克服长距离所带来的噪声和消相干；量子计算机本身的启动就需要大量的量子纠缠源[8]，而运行过程中更是需要大量的基于量子纠缠的量子纠错过程；量子隐形传态和量子密集编码是基于量子纠缠而提出的概念。&lt;br /&gt;&lt;br /&gt;    量子纠缠是发生在多个微观粒子之间的一种物理现象，是指不论粒子间距离多远，一个粒子的态都是与其它粒子的态相关联的，信息大部分都蕴涵在粒子之间的相互关系上，对一个粒子的测量会影响到其它粒子的态，粒子之间不论相距多远，从根本上讲它们还是相互联系的。&lt;br /&gt;&lt;br /&gt;    众所周知，经典信息处理的最基本单元是比特(Bit，即二进制数0或1)。一个按照一定数学规则给出的随机二进制数据串就构成一个密钥，经典通信中信息的安全性依赖于数学问题求解的复杂性, 因而经典密码也就不可能绝对保密。然而，基于量子力学线性叠加原理和不可克隆定理的量子密钥分配却可以解决这个问题。另外，经典计算中存在着一大类NP问题(难解的非指数问题)，即问题的复杂度随着比特位数的增长而指数上升。这类问题在经典计算机上求解非常困难，但是量子计算可以把其中的一部分NP问题变成P问题(容易求解的指数问题)，即问题的复杂度随着比特位数的增长以多项式上升。这类问题原则上是可以计算的。一个具体的例子就是大数分解定理，按经典计算复杂性理论，这个问题不存在有效算法，所以被利用来进行经典密钥分配。但是如果用量子计算机，使用Shor量子算法，这个问题就变成了P问题。例如，为了对一个400位的阿拉伯数字进行因子分解，目前最快的超级计算机将耗时上百亿年，这几乎等于宇宙的整个寿命；而具有相同时钟脉冲速度的量子计算机只需要大约1分钟。因此，对于目前的密码系统，即使人们几乎无法利用经典算法对其进行破解，但一旦人们拥有了一台量子计算机，那么目前的密码系统将毫无保密性可言!这一后果是对目前的密码系统的巨大挑战，因而对基于经典保密系统的行业(如军事、国家安全、金融等)的信息安全构成根本的威胁。因此，为了保证这些领域的信息安全，也为了拓宽人类对微观世界的认识，发展量子信息学刻不容缓：一方面，开发由量子力学基本原理保证其保密性的量子密码系统，另一方面，研制按照量子力学基本原理运行的量子计算机。为此，世界很多国家都投入了巨大的人力和财力积极地进行相关研究。&lt;br /&gt;&lt;br /&gt;    如上所述，量子信息学有着很重大的应用价值，如果实现，将是人类生产力的又一次飞跃。 由于在量子计算中存在着不可避免的噪声, 为了能实现量子计算,需要采用量子纠错技术。理论研究表明，普适的量子纠错需要5个或者更多的粒子的纠缠技术[1，2]。在1999年，潘建伟和他在奥地利的合作者们第一次在实验上制备了3个粒子的纠缠[5，7]，随后在2000年，他们又制备了4粒子的纠缠态[3，4]，并用它们验证了量子力学与定域实在论的矛盾。为了达到5粒子纠缠这一目标，在技术上面临着巨大的挑战。虽然对五光子纠缠的制备及操作的方案在理论上非常明确，但是它的实验实现非常难，迄今为止，自发的参量下转换(SPDC)依旧是最好的纠缠光子源，而且在最近的一些实验中仍被用来作为最基础的纠缠源。然而，由于参量下转换的必然性，导致五光子实验中5体符合计数会非常非常的低。&lt;br /&gt;&lt;br /&gt;    同时，在多粒子量子通讯以及量子计算中有个至关紧要的极具挑战性的实验——开放目的的隐形传态，在所谓的开放目的的隐形传态中，一个未知的单光子态将会被传送到一个N粒子的相干叠加态上，以证明分布式的量子信息处理，接下来，通过对其中N-1个粒子做一定方向的投影测量，原来的这个被传送的未知量子态可以在N个粒子的任何一个粒子上被读出。&lt;br /&gt;&lt;br /&gt;    我们首次报道了在实验上五光子纠缠跟开放目的的隐形传态的原则上实现[10]。在实验中，我们用两对极化纠缠的纠缠光子对来制备一个4光子纠缠态，然后与一个合适亮度的单光子态交迭在一起以得到我们想要的态。为了克服5体符合计数的困难，我们首先在制备高亮度的4光子基础上，进一步改进探测效率，我们可以在合理的时间内收集到足够的实验数据以验证五光子纠缠的存在。&lt;br /&gt;&lt;br /&gt;    我们的实验取得了以下的创新性成果：&lt;br /&gt;&lt;br /&gt;    (1) 首次实验实现五光子纠缠。为了证明五光子GHZ态已经被成功制备，我们在H/V基矢下对32种可能的组成成分做测量，实验结果表明其信噪比平均为40∶1，这证明了在实验的精度下只有我们所希望的HHHHH与VVVVV的成分存在(图1a)；为了进一步验证两种成分确实是相干叠加在一起的，我们对5个光子在+/-基矢下做符合测量，在Delay2在0延迟的情况下两种组合成分+++++与++++-的计数关于Delay1的位置的关系曲线说明了这5个光子确实是五光子GHZ纠缠态。&lt;br /&gt;&lt;br /&gt;    (2) 首次用和五光子纠缠同样的装置实现了开放目标的隐形传态。我们首先制备了4个光子(2，3，4和5)的4体纠缠。将输入的光子1和纠缠态中其中一个光子(光子2)做一个贝尔测量。在随后的实验中，经过适当的操作，光子1的量子态会隐形传输到剩下的3个光子(3，4，或5)中任意一个指定的光子上。在实验中, 对输出的两个出口3、4的光子做45度的投影测量，光子1的量子态会传输到光子5上；同样，对输出的两个出口3、5的光子做45度的投影测量，光子1的量子态会传输到光子4上；对输出的两个出口4、5的光子做45度的投影测量，光子1的量子态会传输到光子3。 为了演示开放目标的隐形传态对光子1的任意态都能工作，我们选择传送45度线性偏振│+〉与│〉, 以及椭圆偏振右旋│R〉与左旋│L〉状态。在实验中，每次测量的时间为10小时，在极化分析测量中，我们所希望得到的5体符合在0延迟时最高计数率约为100的同时最低的计数率约为20，每个点的测量时间均为10小时。我们来看将光子1传送到光子5或者光子4的保真度，我们分别将+/-线性偏振、R/L的圆偏振做光子1的初始状态作隐形传态的测量，对应的保真度参见表1，从中我们可以看到所有观测到传送的保真度(≈0.80±0.04)远远高于经典2/3的限制，从而验证了开放目标的隐形传态。&lt;br /&gt;&lt;br /&gt;    我们的五光子纠缠以及开放目的的超空间传送实验实现的意义是相当深远的。首先，我们的工作是第一次在实验上成功地操纵了5体纠缠态，这是普适的量子纠错所需要的最少的粒子数；其次，开放目的的超空间传送的实现打开了分布式量子信息处理的各种新的可能性；最后，我们的实验技术可以在实验上重新对很多量子方案进行验证，比如比特翻转的量子拒错以及量子计算中最常用的非破坏的控制非门。&lt;br /&gt;&lt;br /&gt;    Nature杂志称赞说，“尽管五粒子纠缠以及终端开放的量子隐形传输的实现非常困难，但是中国科技大学的潘建伟教授和他的同事们完成了这一壮举，他们的实验方法将量子计算和网格化的量子通信中有重要的应用”&lt;br /&gt;&lt;br /&gt;    致谢 该研究得到中国科学院知识创新工程、国家重点基础研究发展规划项目(“973”项目)、国家基金委项目的资助和支持。&lt;br /&gt;&lt;br /&gt;    主要参考文献&lt;br /&gt;&lt;br /&gt;    1 Bennett C H , DiVincenzo D P, Smolin J A et ak. Mixed-state&lt;br /&gt;&lt;br /&gt;    entanglement and quantum error correction. Phys. Rev. A.,1996， 54： 3 824-3 851.&lt;br /&gt;&lt;br /&gt;    2 Laflamme R, Miquel C, Paz J P et ak. Perfect Quantum Error&lt;br /&gt;&lt;br /&gt;    Correcting Code. Phys. Rev. Lett., 1996，77： 198-201.&lt;br /&gt;&lt;br /&gt;    3 Sackett C A et ak. Experimental entanglement of four particles.&lt;br /&gt;&lt;br /&gt;    Nature， 2000， 404： 256-259.&lt;br /&gt;&lt;br /&gt;    4 Pan J W, Daniell M, Gasparoni S et ak. Experimental&lt;br /&gt;&lt;br /&gt;    demonstration of four-photon entanglement and high-fidelity&lt;br /&gt;&lt;br /&gt;    teleportation. Phys. Rev. Lett., 2001， 86：4 435-4 439.&lt;br /&gt;&lt;br /&gt;    5 Pan J W, Bouwmeester D, Daniell M et ak. Experimental test&lt;br /&gt;&lt;br /&gt;    of quantum non-locality in three-photon Greenberger-&lt;br /&gt;  Horne-Zeilinger entanglement. Nature 2000， 403： 515-519.&lt;br /&gt;&lt;br /&gt;    6 Bennett C H et ak. Teleporting an unknown quantum state via&lt;br /&gt;&lt;br /&gt;    dual classical and Einstein-Podolsky-Rosen channels. Phys.&lt;br /&gt;&lt;br /&gt;    Rev. Lett., 1993， 83： 3 081-3 084.&lt;br /&gt;&lt;br /&gt;    7 Zeilinger A, Horne M A, Weinfurter, H et ak. Three-particle&lt;br /&gt;&lt;br /&gt;    entanglements from two entangled pairs. Phys. Rev. Lett.,1997，78： 3 031-3 034.&lt;br /&gt;&lt;br /&gt;    8 Knill E, Laflamme R, Milburn G J. A scheme for efficient&lt;br /&gt;&lt;br /&gt;    quantum computation with linear optics. Nature, 2001， 409：&lt;br /&gt;&lt;br /&gt;    46-52.&lt;br /&gt;&lt;br /&gt;    9 Bouwmeester D et ak. Experimental quantum teleportation.&lt;br /&gt;&lt;br /&gt;    Nature， 1997， 390, 575-579.&lt;br /&gt;&lt;br /&gt;    10 Zhi Zhao et ak. Experimental demonstration of five-photon&lt;br /&gt;&lt;br /&gt;    entanglement and open-destination teleportation Nature,2004， 430： 54-58.&lt;br /&gt;&lt;br /&gt;    杨 涛 潘建伟&lt;br /&gt;&lt;br /&gt;    (中国科学技术大学 合肥 230026)&lt;br /&gt;&lt;br /&gt;    摘要 由中国科技大学合肥微尺度国家实验室(筹)量子物理和量子信息部所完成的“五光子纠缠和开放目的的量子隐形传态”研究成果以Letter的方式发表在2004年7月1日出版的Nature上，欧洲物理学会和美国物理协会都对该工作进行了专题报道。本文介绍了该成果的研究背景，意义，内容。&lt;br /&gt;&lt;br /&gt;    成果与应用&lt;br /&gt;&lt;br /&gt;    Experimentak Demonstration of Five-photon Entangkement and Open-destination Tekeportation&lt;br /&gt;&lt;br /&gt;    Yang Tao Pan Jianwei&lt;br /&gt;&lt;br /&gt;    (University of Science and Technology of China 230026 He Fei)&lt;br /&gt;"Experimental Demonstration of Five-photon Entanglement and Open-destination Teleportation" finished by the department of Quantum Physics and Quantum Information of Hefei National Laboratory for Physical Sciences at Micro scale of USTC was published in nature on July 1st 2004. This progress was also reported by European Physical Society's website——Physics Web and American Physical Society. This article is about its background, signification and its detail contents.&lt;br /&gt;&lt;br /&gt;    Keywords entanglement, interference, teleportation&lt;br /&gt;&lt;br /&gt;    课题组负责人简介： 潘建伟 男，中国科技大学教授，博士生导师。1970年出生。1998年获奥地利维也纳大学物理学博士学位。2001年，入选“中科院引进国外杰出人才”，并获国家杰出青年基金。2002年，被国家教育部聘为“长江学者”。2003年，由于在量子态隐形传输以及量子纠缠态纯化实验实现上的重要贡献，被奥地利科学院授予青年物理学家最高奖——Erich Schmid奖。关于“量子态隐形传输实验研究”的工作分别于1997年入选欧洲物理学会“年度国际十大物理学新闻”、美国物理学会“年度国际十大物理学新闻”；于1998年入选美国Science “年度国际十大科技新闻”；于1999年入选英国 Nature 特刊“百年物理学21篇经典论文”、入选国家科学技术部“1999年基础研究十大新闻”。关于“三光子纠缠态以及量子力学非定域的实验检验”的工作于2000年入选美国物理学会“年度国际十大物理学新闻”。到目前为止，已在 Nature 发表论文6篇， Physicak Review Letters 上发表论文10余篇。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-117005739175857064?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/117005739175857064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/117005739175857064'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2007/01/some-notes-on-quantum-communication-1.html' title='Some notes on quantum communication - 1'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-117005629515152650</id><published>2007-01-07T23:33:00.000-08:00</published><updated>2007-01-28T23:38:15.203-08:00</updated><title type='text'>Some notes on single-photon for communication</title><content type='html'>1.&lt;br /&gt;世界首次通信波段的单一光子发生获得成功&lt;br /&gt;&lt;br /&gt;东京，2004年7月27日 — 东京大学先端科学技术研究中心的生产技术研究所纳电子联合研究中心(1)的荒川泰彦教授小组与株式会社富士通研究所(2)共同开发出单一光子(3)的发生检测系统，并首先在世界通信波段中的单一光子的开发中获得成功。根据此次开发的技术，被称为临界状态的密码通信手段由以往的每秒仅限于100位（以下称为bps）的量子密码通信(4)速度被一气提高到其400倍以上的高速度，其成果面可谓向量子密码通信的实用化大幅度向前迈进了一步。 &lt;br /&gt;&lt;br /&gt;此次研究开发的一部分被作为日本文部科学省IT项目予以实施。&lt;br /&gt;&lt;br /&gt;该技术成果首先发表在7月15日发行的JJAP(Japanese Journal of Applied Physics) Express Letter上。并且，该技术的详细内容于7月26日在美国亚利桑那州召开的半导体物理国际会议（International Conference on the Physics of Semiconductors；ICPS-27)上得以发布。 &lt;br /&gt;&lt;br /&gt;此外，该技术的一部分是作为日本文部科学省的研究开发委托事业-「IT程序～世界最先进IT国家实现重点研究开发项目～」中的课题之一的「光·电子装置技术的开发项目」予以研发的，同时，得到了独立行政法人物质·材料研究机构-纳材料研究所(5)的鼎力协助。 &lt;br /&gt;&lt;br /&gt;【开发背景】&lt;br /&gt;&lt;br /&gt;随着互联网上的电子商务的普及，对通讯安全的需求日益高涨。其中，量子密码通信技术作为可将盗听的可能性降低至零的高度安全的临界密码通信手段，其研究开发活动在世界各地积极展开。&lt;br /&gt;&lt;br /&gt;【研究课题】&lt;br /&gt;&lt;br /&gt;为实现量子密码通信，需开发出能够将1脉冲所含的光子控制为1个的单一光子发生器。但是，由于实际应用中光纤通讯的波长段（1.3-1.55微米）中没有单一光子的发生技术，所以在以往的量子密码通信试验中，不得不使用通常的激光光源来代替单一光子。&lt;br /&gt;&lt;br /&gt;但是，量子密码通信中所用的激光光源会使2个以上的光子进入到1脉冲内，从而无法将盗听的可能性降低为零。为了降低2个以上的光子进入1脉冲内的概率，需要降低光源的强度，因此，在使用激光光源的量子密码中便存在着如何提高目前远程通讯速度的100bps这一巨大问题。&lt;br /&gt;&lt;br /&gt;【开发技术】&lt;br /&gt;&lt;br /&gt;此次开发的内容，是利用1.3至1.55微米的具有实用性的通信波长段发生并测量单一光子的技术。开发技术的特长如下：&lt;br /&gt;&lt;br /&gt;1．使用通信波长带的单一光子发生技术 (图1) &lt;br /&gt;&lt;br /&gt;http://www.fujitsu.com/img/CN/news/2004/0727_1.gif   &lt;br /&gt; &lt;br /&gt; 图1：产生单一光子的半导体单元  &lt;br /&gt;&lt;br /&gt;使用光学仿真，从被称作量子粒的纳米尺寸的结构中，设计出了可有效发生光子的半导体单元。同时，新开发出了对极小结构的量子粒不产生损伤的半导体工序技术。根据这一成果，以往无法实现的利用通信波长段发生单一光子便成为可能。所使用的量子粒是由独立行政法人「物质·材料研究机构 纳材料研究所」的佐久间主任领导的研究小组与富士通研究所共同开发、制作出来的。 &lt;br /&gt;&lt;br /&gt;2．使用通信波长段的单一光子的检测技术 (图2) &lt;br /&gt;&lt;br /&gt;http://www.fujitsu.com/img/CN/news/2004/0727_2.gif &lt;br /&gt;&lt;br /&gt; 图2：单一光子检测系统示意图  &lt;br /&gt;&lt;br /&gt;为了能够提高新开发的半导体单元的聚光效果，又设计并开发出可将光子脉冲放出的光传输到通讯光纤上的单一光子发送系统。此外，将通过光纤的光束分为2股，设计开发出可准确检测2股光束的接收时间的单一光子接收系统。通过确认2股光束不被同时检测到，可证明发生的光束就是单一光子。&lt;br /&gt;&lt;br /&gt;【实验结果和效果】&lt;br /&gt;&lt;br /&gt;利用此次开发的系统进行实验，得出了这样的结论，即2股光束在被同时检测时，其干扰误差的范围为零，从而证明了使用通信波长带，可从量子粒中发生单一光子这一事实。（图3）。 &lt;br /&gt;&lt;br /&gt;http://www.fujitsu.com/img/CN/news/2004/0727_3.gif&lt;br /&gt; &lt;br /&gt; 图3：单一光子检测的实际结果  &lt;br /&gt;&lt;br /&gt;此外，虽然此次验证的单一光子的光波长为1.3微米，但是也可以观测到通常使用的通信波长为1.55微米的量子粒的发光。&lt;br /&gt;&lt;br /&gt;通过利用通信波长段检测单一光子的发送，即使发送方的发光强度减弱，也可以保证量子密码的通信。根据这一特性，在100公里的通信距离中，其通信能力是以往使用激光光源的量子密码通信的约400倍，达到100kbps，在信息安全要求严格的政府机构、金融、医疗等领域中，实现了量子密码通信技术的实用化的飞跃性提高。&lt;br /&gt;&lt;br /&gt;【今后】&lt;br /&gt;&lt;br /&gt;今后，为验证波长为1.55微米的单一光子的传输，并提高单一光子的提取效率，大约2007年左右，实现单一光子发生器的实用化这一目标，我们正锐意推进相关的研发工作。此外，面对量子网络的建设，量子中转技术及量子计算技术的开发也在实施中。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-117005629515152650?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/117005629515152650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/117005629515152650'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2007/01/some-notes-on-single-photon-for.html' title='Some notes on single-photon for communication'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-117005589347754993</id><published>2007-01-06T23:28:00.000-08:00</published><updated>2008-01-29T04:00:19.678-08:00</updated><title type='text'>Some notes on quantum machine - 1</title><content type='html'>真的不知道有多少人在看我的blog，反正我本意是留给自己看的。不过扫了一眼流量，还是继续吧。&lt;br /&gt;&lt;br /&gt;本月专题 量子计算机和量子保密通讯&lt;br /&gt;&lt;br /&gt;I.&lt;br /&gt;From http://www.frontfree.net/view/article_724.html 原文有图&lt;br /&gt;&lt;br /&gt;量子计算机发展简史 &lt;br /&gt;原著：Simon Bone &amp; Matias Castro 翻译：bianca  2003年3月26日  &lt;br /&gt; &lt;br /&gt;&lt;br /&gt;内容摘要&lt;br /&gt;听起来好像有点奇怪，计算机的未来可以被建筑在一杯咖啡周围。那些咖啡因分子恰巧是构建“量子计算机”－－一种能够保证提供可在几秒钟内破解密码的思想回应功能的新型计算机的可能组成部件。&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;内容目录&lt;br /&gt;1.介绍 &lt;br /&gt; 1.1量子计算机的基本要素 &lt;br /&gt; 1.2量子计算机的缺点－－(电子)脱散性 &lt;br /&gt; 1.3取得结果 &lt;br /&gt;2.通用计算的理论 &lt;br /&gt; 2.1加热流失的信息 &lt;br /&gt; 2.2通用量子计算机 &lt;br /&gt; 2.3人工智能 &lt;br /&gt;3.建立一台量子计算机 &lt;br /&gt; 3.1量子点 &lt;br /&gt; 3.2计算流体 &lt;br /&gt;4.量子计算机的应用 &lt;br /&gt; 4.1Shor算法－－Shor的算法－－一个范例 &lt;br /&gt; 4.2Grover算法 &lt;br /&gt; 4.3量子机械系统的模拟 &lt;br /&gt;5.量子通讯 &lt;br /&gt; 5.1量子通讯是如何工作的 &lt;br /&gt; 5.2量子比特的任务 &lt;br /&gt;6.当今进展及未来展望 &lt;br /&gt;7.结论 &lt;br /&gt;8.术语表 &lt;br /&gt;9.参照表 &lt;br /&gt; 9.1书籍 &lt;br /&gt; 9.2人物 &lt;br /&gt; 9.3杂志文章 &lt;br /&gt; 9.4网页 &lt;br /&gt;&lt;br /&gt;1.介绍&lt;br /&gt;经常会有能使计算机的性能大大改善的新技术出现。从晶体管技术的引进，到超大规模集成电路的持续性发展，科技进步的速度总是如此无情。近日来，现代处理器中晶体管体积的减小成为计算机性能改进的关键所在。然而，这种不断的减小并不能够持续很长的时间。如果晶体管变得太小，那种对量子机械的未知影响将会限制它的性能。因此，看起来这些影响会限制我们的计算机技术，它们真的会吗？ 在1982年，诺贝尔奖获得者－－物理学家Richard Feynman想出了 “量子计算机” 的概念，那是一种利用量子机械的影响作为优势的计算机。有一段时间，“量子计算机”的想法主要仅仅停留在理论兴趣阶段，但最近的发展令这个想法引起了每一个人的注意。其中一个进步就是一种在量子计算机上计算大量数据的算法的发明，由Peter Shor(贝尔实验室)设计。通过使用这种算法，一台量子计算机破解密码可以比任何普通(典型)计算机都要快。事实上，一台能够实现Shor算法的量子计算机能够在大约几秒内破解当今任何密码技术。在这种算法的推动下，量子计算机的话题开始集中在动力上，全世界的研究人员都争当第一个制造出实用量子计算机的人。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1.1量子计算机的基本要素&lt;br /&gt;&lt;br /&gt;在计算机的经典模型中，最基础的构建要素－－比特，只能存在于两种截然不同的状态之一：0或是1。在量子计算机中，规则改变了。一个原子比特－－经常被简称为 “量比”(quantum bit) －－不仅仅存在于传统的0和1状态中，还可以是一种两者连续或重叠状态。当一个量比处于这种状态时，它可以被认为存在于两种领域中：一种为0，而另外一种为1。一个基于这种量比的操作能够同时有效地影响两个值。因此，极为重要的一点是：当我们在量比上实行单一操作时，我们是在针对两种不同的值进行的。类似的，一个双量比系统能对4个值进行操作，而一个三量比系统就是8个值。因此，增加量比的数目能够以指数方式增加我们从系统获得的“量子并行效应”(量子并行效应)。在拥有正确算法类型的情况下，它能通过这种并行效应以远低于传统计算机所花费的时间内解决特定的问题。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1.2量子计算机的缺点－－(电子)脱散性&lt;br /&gt;&lt;br /&gt;使量子计算机如此强大的关键要点是，它对受量子机械规律决定的奇异的亚原子事件的依赖，而这也使它非常脆弱和难以控制。例如，假想一个处于连续状态的量比。一旦它和环境发生了可调节的相互影响，它就将脱散并落入两种传统状态中的一种，这就是脱散性问题。它已经成为了量子计算机作为建立在由连续性状态所带来的量子并行效应上的潜在力量的绊脚石。这个问题很复杂，即使只是看看量比也会引起它的脱散，这使从一台量子计算机获得结果的过程像量子计算机自己做运算一样难。&lt;br /&gt;&lt;br /&gt;1.3取得结果&lt;br /&gt;当一个利用量子并行效应的计算执行后，不同的领域将会得到许多不同的结果。事实上，我们只能通过关注各种结果之间的冲突来获得一个计算的结果。值得注意的是：关注一台量子计算机的结果(或者任何中间状态)将会阻止任何不同版本之间进一步冲突的发生。例如，可以阻止任何有用的量子计算继续进行。这种冲突可以用一个简单的例子来表明：在托马斯.杨(Young)的双缝干涉试验中，光通过两条平行细缝照向屏幕。展现在屏幕上的明暗条纹的图案是相长和相消的结果。用类似的方法，每种状态的计算结果都相长和相消出一个可以测量的结果。这个结果对于不同的算法有着不同的重要性，并且可以用于手工推算问题结果(例如：见Shor's algorithm - An example)。&lt;br /&gt;&lt;br /&gt;图1 托马斯.杨(Young)的双缝干涉试验演示了光子的干涉。&lt;br /&gt;&lt;br /&gt;2.通用计算的理论&lt;br /&gt;所有计算机，从Charles Babbage的分析解析机(analytical engine)(1936)到建立在PC基础上的Pentium(tm)，它们的共性之一，是在Alan Turing的著作中所阐述的古典计算理论。事实上，Turing的著作描述了通用的图灵机的概念，一种非常简单的计算机模型，它能够被设计用来执行任何被自然地认为可计算的操作。所有的计算机都必然能够实现通用图灵机。尽管它们中的有些可能比其它的更快、更大或更昂贵，但它们在功能上是相同的，它们都能执行同样的计算任务。&lt;br /&gt;&lt;br /&gt;2.1加热流失的信息&lt;br /&gt;大量的时间都被花费在研究量子理论是否在计算机器上设置了基本限制。结论是，现在普遍相信：物理学并未在计算机器速度、可靠性和记忆容量上设置任何绝对的限制。然而，有一点需要考虑的是，信息可能在计算过程中被丢失。为了使一台计算机能够运行得快，它的操作必须是可逆的。(例如，它的输入必须完全可以从它的输出推出来)。这是因为不可逆的计算将会引起一种可换算成熵的信息的丢失，因此，系统散热的有限能力将会反过来限制计算机的性能。一个信息丢失的例子是一种常见的与门。一个与门有两个输入而只有一个输出，这就意味着在从输入门移动到输出门的过程中，我们损失了一比特的信息。&lt;br /&gt;&lt;br /&gt;1976年，Charles Bennett证明了可以利用非门建立一种通用计算机，这种计算机在表示具有原始可逆操作的程序时不会降低它的速度。而有一种合适而且通用的非门可以用来制造计算机－－Toffoli门(见图2)。&lt;br /&gt;&lt;br /&gt;图2Toffoli门的输入是完全可以从它的输出推断出来的。&lt;br /&gt;&lt;br /&gt;2.2通用量子计算机&lt;br /&gt;Church-Turing理论：“存在或者可以制造一种计算机，这种计算机能够被设计进行任何自然物体能够进行的计算。”&lt;br /&gt;&lt;br /&gt;在量子计算理论中，已经取得了一系列重大进步。第一个是由Richard Feynman在1982年发现的：一个简单级别的通用模拟器能够模拟任何既定的自然物体的行为。1984年，David Albert做出了第二个发现：他描述了一种“自我调节量子机器人”，这种机器人能够执行任何传统计算机都无法模仿的任务。通过指导这种机器人进行自我调节，它能够获得仅靠从外界环境进行度量绝对无法获得的“主观”信息。最后而且可能也是最重要的发现是由David Deutsch在1989年做出的，他证明了所有既定计算机的计算能力遵从于量子计算机的规则，一种可以从一台单一的通用量子计算机中获得的规则。这种计算机可以通过Toffoli门的量子等价以及添加一些能够带来0和1状态的线性重叠的操作来实现。这样，一台通用量子计算机就完成了。这个发现需要对Church-Turing理论：“存在或者可以建造一种计算机，这种计算机能够被设计进行任何自然物体能够进行的计算。”进行一点调整。&lt;br /&gt;&lt;br /&gt;2.3人工智能&lt;br /&gt;量子计算理论和人工智能领域有一些有趣的联系。对于一台计算机是否真的能实现人工智能的争论已经持续了数年，并且很大程度上是哲学的争论。那些反对这种观点的人解释说：人类的思想，即使只是在理论上，也不可能在图灵机上实现的。&lt;br /&gt;&lt;br /&gt;量子计算理论允许我们从一个有些微不同的视角来看待意识问题。首先值得注意的是，任何自然物体，从一块岩石到整个宇宙，都可以被看做是一台量子计算机；而任何可察觉的自然过程都可以被视为一种计算。在这些标准下，大脑可以作为一台计算机而意识就是一种计算。争论的下一个阶段主要是基于Church-Turing理论，并且证明：因为每一台计算机在功能上都是等价的，每台既定的计算机一定能模仿其它的计算机，所以用一台量子计算机模仿意识理性思维必然是可能的。&lt;br /&gt;&lt;br /&gt;一些人相信量子计算机是突破人工智能问题的关键所在，但是另外一些人不同意。牛津大学的Roger Penrose认为，意识需要一种更奇特的(也是未知的)物理学。&lt;br /&gt;&lt;br /&gt;3.建立一台量子计算机&lt;br /&gt;一台量子计算机在设计上没有什么类似传统计算机，例如你不能使用晶体管和二极管。为了制造一台计算机就需要产生一种新的技术，一种能使“量比”在0和1之间以连贯重叠的状态存在的技术。尽管实现这个目标的最优方法仍然是未知的，但已有许多方法在实验中，并被证明取得了不同程度的成功。&lt;br /&gt;&lt;br /&gt;3.1量子点&lt;br /&gt;一个量比执行的范例是“量子点”，它基本上是一个被困在原子牢笼中的单一电子。当量子点暴露在刚好合适波长的激光脉冲下并持续一段时间，电子就会达到一种激发态：而第二次的激光脉冲又会使电子衰落回它的基态。电子的基态和激发态可以被视为量比的0和1状态，而激光在将量比从0状态撞击到1状态或从1撞击到0的应用，能够被看成是一种对取非功能的控制。&lt;br /&gt;&lt;br /&gt;如果激光持续时间只有取非功能要求的一半，那么电子将同时处于基态和激发态的重叠中，这也等价于量比的连贯性状态。而更多复杂的逻辑功能可以通过使用成对的安排好的量子点被模拟出来。因此，看起来量子点是一个合适的建造量子计算机的候选人。然而不幸的是，有许多实际问题阻止了这种情况的发生：&lt;br /&gt;1.电子在衰落回基态之前只能在激发态维持一微秒(百万分之一秒)。需要记住的是，每种激光脉冲需要持续的时间大约是1纳秒。这就对在信息散失前所能做出的运算步骤的数量有了限制。&lt;br /&gt;2.构建量子点是一个非常艰难的过程，因为它们如此微小，而使用这些量子点制造一台计算机的技术到目前为止还不存在。&lt;br /&gt;3.为了避免数以千计的激光射入一个狭小的空间，量子点应当制造以回应不同频率的光。一束能够可靠地进行自我调整的激光将会选择性地瞄准有着不同光频率特性的不同组别的量子点。又一次的，这是一项还不存在的技术。&lt;br /&gt;&lt;br /&gt;3.2计算流体&lt;br /&gt;量子点并不是唯一的经过试验的执行量比，其它技术试图使用个体原子或激光的分化作为信息的媒体，而脱散性是这些技术的普遍问题。人们尝试将这些实验从它们周围环境屏蔽起来，例如在千分之一的绝对零度的温度下将其冷却，然而这些方法在减少这个问题的影响方面取得了极其有限的成功。&lt;br /&gt;&lt;br /&gt;量子计算领域的最新发展采用了一个根本性的新方法。这种方法放弃了量子媒质应当小并且和它的周围环境隔离的假设，而是使用大量的分子来储存这些信息。当处于磁场中时，一个分子中的每个核子都会在一个特定方向上的旋转，这个旋转特性可以用来描述它的状态，上旋表示1而下旋代表0。核子磁性共振技术可以被用来检测这些旋转状态，特殊无线电波脉冲能够把核子从上旋(1)撞击到下旋(0)，反之亦然。&lt;br /&gt;&lt;br /&gt;使用这种技术的量子计算机本身就是一个分子，而它的量比就是分子内的那些核子。但是这种技术并不能只使用一个单一分子来实现这些计算，而是用一整“杯”流体分子。这种方法的优势在于，即使液体分子彼此撞击，每个分子中核子的旋转状态仍能保持不变。脱散性仍然是一个问题，但是到目前为止，在这种技术中脱散前的时间已经比任何其它技术的时间要长许多。研究人员相信，几千个原始逻辑操作能够在量比脱散前实现。&lt;br /&gt;&lt;br /&gt;麻省理工学院的Dr.Gershenfield，是流体计算技术的倡导者之一。他的研究队伍已经能够将1和1加起来，这是一个远远超越其它任何正在研究中的技术能力的简单任务。而能够计算更复杂任务的关键在于拥有更多的原比，但是这要求更多复杂的分子以及大量的核子，因此咖啡因分子成为一个可能的候?Ｎ蘼壅庵址肿邮鞘裁矗?0量比系统的进步都是显而易见的。Dr.Gershenfield希望这样一个系统在年底，将能够乘以数字15。&lt;br /&gt;&lt;br /&gt;超过10量比系统的进步可能会更加困难。在一个给定的“计算流体”样本中，将会有大约偶数个上下旋状态，但是将会有一点在超过一个方向上的旋转存在。正是这些少量额外旋转的所发出的表现得好像它是一个单一分子的信号，使它能够被检测出来以及进行运算操作，而剩下的旋转将会有力地彼此抵消掉。这种信号相当微弱，并且在每个量比被加入的时候，以大约2倍的速度持续性减弱。这就会限制一个系统可能拥有的量比的数目，而易读的输出将会更难以检测出来。&lt;br /&gt;&lt;br /&gt;4.量子计算机的应用&lt;br /&gt;非常需要注意的是，一台量子计算机并不一定在所以计算任务上都会比一台传统计算机做得好。例如，乘法运算在一台量子计算机上执行的不比在一台类似的传统计算机上快。为了显示量子计算机的优越性，就需要使用开发量子并行效应能力的算法。这些算法难以阐述，而值得记住的最显著理论化的算法当属Shor的算法和Grover的算法。通过使用好这些算法，量子计算机能够大大优于传统计算机。例如，Shor算法允许以极快的速度因式分解大数字。一台传统计算机在分解1000位阿拉伯数字时需要花费10,000,000,000,000,000,000,000,000年，而一台量子计算机只需大约20分钟。&lt;br /&gt;&lt;br /&gt;4.1Shor算法－－Shor的算法－－一个范例&lt;br /&gt;这是Peter Shor在1995年发明的算法，它能够快速地分解大数字。如果它曾经被使用过，它将会对密码系统有着深刻的影响，它会威胁到由公钥密码学所提供的安全性(例如RSA)。&lt;br /&gt;&lt;br /&gt;受到威胁－－公钥密码学&lt;br /&gt;这是当前最常用的发送密码数据的方法。它通过使用两把密钥来工作，一把公开的，一把私人的。公开的密钥用来给数据加密，而私人的密钥用来解密。公开的密钥可以容易地从私人的密钥获得，而反之却不可能。然而，一个掌握着你公开密钥的窃听者原则上可以计算出你的私人密钥，因为它们在数学上是相联系的。为了破解私人密钥，需要分解公开密钥，然而这项任务被认为是无法处理的。&lt;br /&gt;&lt;br /&gt;例如，1234乘以3433容易算出来，但计算4236322的因子就不那么容易了。分解一个数的质因子的计算复杂度随该数增长而迅速膨胀。破解RSA129(有129位阿拉伯数字)时，花费了1600位因特网用户8个月的时间。密码破译着认为，更多的数字应当被加到密钥中以抵抗计算机性能的增长(这将花费比宇宙年龄还长的时间来计算RSA140)。然而，对于使用运行Shor算法的一台量子计算机，密钥中的阿拉伯数字个数对问题的难度有着极小的影响。破译RSA140只需花费几秒钟的时间。&lt;br /&gt;&lt;br /&gt;Shor算法－－一个范例&lt;br /&gt;这部分的目的是说明Shor算法有关的基本步骤。为了使问题相对简单易懂，我们将考察找到数字15的质因子问题。因为算法主要由三步组成，讲解将会分为3个阶段...&lt;br /&gt;&lt;br /&gt;阶段1&lt;br /&gt;&lt;br /&gt;算法的第一个阶段是将记忆寄存器放入一段它所有可能状态的连贯重叠中。字母“Q”将会用来表示一个处于连贯状态的量比。&lt;br /&gt;&lt;br /&gt;图3 一个3量比寄存器可以同时表示8个传统状态&lt;br /&gt;&lt;br /&gt;当一个量比处于连贯状态中，它可以被认为存在于两个不同的领域中。它作为“1”存在于一个领域中，而在另一个领域中，以“0”存在(见图1)。将这种想法扩展到3比特寄存器，我们可以想像为寄存器存在于8种不同的领域，在每个领域都可以表现一种传统的状态(例如，000, 001, 010, 011, 100, 101, 110, 111)。为了储存数字15，需要一个4比特的寄存器(能够同时在连贯状态下表现数字0到15)。&lt;br /&gt;&lt;br /&gt;在寄存器上执行的计算可以被当做并行的一整组计算，每个领域一个。事实上，一个在寄存器上执行的计算是执行在寄存器所能够表现的所有可能值上的。&lt;br /&gt;&lt;br /&gt;阶段2&lt;br /&gt;&lt;br /&gt;第二个阶段的算法使用寄存器执行一个运算。运算细节如下：&lt;br /&gt;1.数字N是我们希望分解的，N=15。&lt;br /&gt;2.挑选一个随机数N，1 &lt; X &lt; N-1。&lt;br /&gt;3.X达到存放在寄存器(寄存器A)中的大小，然后除以N。&lt;br /&gt;4.这个操作的余数被放在第二个位寄存器中(寄存器B)。&lt;br /&gt;&lt;br /&gt;图4 第二阶段的操作&lt;br /&gt;&lt;br /&gt;这个操作之后，寄存器B包含有各个领域结果的叠加。这可以通过一个例子来极好的证明：如果我们令X为2，那么寄存器B中对应于寄存器A中的每个可能值的内容如下。&lt;br /&gt;&lt;br /&gt;表格1 寄存器B的内容，N=15, X=2。&lt;br /&gt;注意到寄存器B的内容符合一个重复的序列(1,2,4,8,1,2,4,8...)，而这些重复的频率可以被称作f。在当前这种情况下，重复的频率(1, 2, 4, 8)有4个值，所以f=4。&lt;br /&gt;&lt;br /&gt;阶段3&lt;br /&gt;&lt;br /&gt;最后一个阶段可能是最难以理解的。重复的频率，f，在使用一台量子计算机时将会被发现，这是通过在寄存器B上执行一个复杂的操作，然后察看那些引起每个领域的结果彼此干扰的内容实现的。作为f的结果而发生的值在接下来的等式中被使用，以计算一个可能的质因子。&lt;br /&gt;&lt;br /&gt;图5 用来计算质因子的等式&lt;br /&gt;&lt;br /&gt;结果数字并不能保证它是一个质因子，但是是的可能性很大。而生成f值的干扰容易使正确答案作为不正确的答案而互相抵消掉。&lt;br /&gt;&lt;br /&gt;在我们的例子中，f=4的值确实给出了一个正确的结果3。&lt;br /&gt;&lt;br /&gt;答案并不能保证正确的事实并不重要，因为它可以通过乘法很容易地检查出来。如果答案是错误的，用不同的X值重复上述计算将会很有可能得到正确的解。&lt;br /&gt;&lt;br /&gt;4.2Grover算法&lt;br /&gt;Lov Grover曾经写过一个算法，使用量子计算机用比传统计算机快的速度检索一个未排序的数据库通常，这需要花费N/2个数字的时间来在一个具有N个入口的数据库中搜索发现一个特定的入口。Grover的算法使在N叉检索中进行相同的搜索变得可能。随着数据库的规模和综合程度增长，这种时间上的节省变得具有显著意义。这种算法所带来的加速是量子并行结构的结果。数据库有效地分布在大量的领域，并且允许一次单一的搜索定位要求的入口。更多数量的操作(与叉N成比例)要求实现，以满足显示一个可读结果的要求。&lt;br /&gt;&lt;br /&gt;Grover的算法在密码系统领域有着重要的应用。使用这种算法破解数据加密标准(DES)，一种用来保护银行间的经济事务及其它事物的标准，在理论上是可能的。这个标准是建立在一个双方都事先知道的56-比特的数字的基础上的，这个数字被用作加密和解密数据的密钥。&lt;br /&gt;&lt;br /&gt;如果一个加密文档及它的原始资料都可以获得，那么就可能找到那个56-比特的密钥。一个使用传统方式的穷举搜索必须在找到正确解前搜索2的55次方个密钥。即使每秒钟尝试10亿个密钥，也需要花费超过一年的时间，而相比较而言Grover的算法找到密钥只需185次检索。对于传统的DES，一种阻止现代计算机破解密码的方法(例如，如果计算机越来越快)，仅仅只要在密钥上添加额外的数字，就会使搜索的次数呈指数增长。然而，这对于量子算法速度的影响是可以忽略不计的。&lt;br /&gt;&lt;br /&gt;4.3量子机械系统的模拟&lt;br /&gt;1982年，Feynman推测说，量子计算机将能够比传统计算机更大程度地精确模拟量子机械系统。据推测，一台拥有几十个量子比特的量子计算机能够进行模拟，而这对于一台传统计算机来说，所需的时间是不现实的。这应当归因于计算机时间和内存的使用是按照讨论中的量子系统的规模呈指数增长的。&lt;br /&gt;&lt;br /&gt;对于传统计算机，一个量子系统的动力学可以用近似值模拟。然而，一台量子计算机能够被“设计”，通过诱使它的变量发生交互作用来模拟一个系统的行为。它们模拟了正在讨论中的系统特性。例如，一台量子计算机能够模拟“笋瓜模型”(一种描述电子在晶体中移动的模型)，而这样的任务是超出当今传统计算机的工作范围的。&lt;br /&gt;&lt;br /&gt;5.量子通讯&lt;br /&gt;在量子计算方面的研究开创了无旋转领域的量子沟通。这部分研究的目标是通过使用量子机械影响的特性，提供安全可靠的通讯设施。&lt;br /&gt;&lt;br /&gt;5.1量子通讯是如何工作的&lt;br /&gt;量子通讯利用光的偏振(例如，一个光子振动的方向)对数据进行编码。在一个方向上的振动可以被视为0，而另一个为1。常用的有两种偏振方式，直线型和对角型(见图6)。&lt;br /&gt;&lt;br /&gt;图6 光的偏振可以被用来对数据进行编码。为了接收数据，滤光器的偏振化方向必须与光子的相匹配。&lt;br /&gt;&lt;br /&gt;量子通讯开发的特性是，为了接收正确的信息，必须测量光子并使用正确的滤光器偏振方向。例如，和信息传送的偏振方向相同。如果一个接收器是处于直线型的偏振方向，那么就会发射出对角偏振的光子，然后一个完全随机的结果就会出现在接收器上。使用这种方法，特性信息能够发送而使窃听者无法不被发现地偷听。这种机械装置工作原理如下：&lt;br /&gt;&lt;br /&gt;1.发送者用随机偏振方式传送信息至接收者。&lt;br /&gt;2.接收者检测这个信息并记录下来(仍然使用随机偏振方式)。&lt;br /&gt;3.然后，发送者通过公共线路通知接收者他所使用的偏振方式。&lt;br /&gt;4.接收者和发送者对在正确偏振方式下获得的信息进行随机选取，进行比较。&lt;br /&gt;5.如果一个窃听者中途截取并转寄信息，那么错误发生的比率将会比预期的要高，这就会引起接收者和发送者的警觉。&lt;br /&gt;6.如果检测出窃听者，那么整个过程将会被重复。&lt;br /&gt;&lt;br /&gt;例如，假设有一个发送者叫Alice，她希望传送信息给Bob而不希望被窃听者Eve听到。他们就会遵循上述步骤。如果Eve试图偷听，她就需要测量来自Alice的比特，然后再转寄给Bob(她不能仅仅察看信息，因为这样做会改变信息内容)。她必须使用随机偏振方式，因为她不知道Alice所使用的。可能，Eve会接收到50%的正确信息，而另外的50%由随机的值组成。而大约一半的随机值是正确的，这意味着Eve最好情况下可以将75%的正确信息发送给Bob。&lt;br /&gt;&lt;br /&gt;假设通讯线路上的噪音是可以忽略的，Bob将能够检测出Eve偷听了，因为他按照正确的偏振方向所收到的信息包含超过25%的错误。他通过和Alice在公共线路上对随机选取的信息进行比较以检测错误。&lt;br /&gt;&lt;br /&gt;另外一种Eve搅乱Bob和Alice通讯的方法是中途截取信息，再将她自己的发送出去。Alice和Bob讨论的一组随机选择的值将会阻碍Eve，并暴露出Eve修改了信息。无论Eve截取的信号有多么微小，Alice和Bob总能够发现她在线上偷听。这个系统只能在通讯线路的噪音可以忽略的情况下工作。如果线路有，例如25%的噪音，就无法将窃听者从噪音中区分出来。英国电信已经成功地实现了在超过10公里的距离上只有9%的错误的线路，这为量子通讯提供了一个具有希望的未来。&lt;br /&gt;&lt;br /&gt;5.2量子比特的任务&lt;br /&gt;一个量子通讯不同的方法是量子比特的任务。使用这种方法，人们可以比较或结合信息，同时保持每个独立文献的隐秘性。这种技术的一个可能应用是合同出价(令公司提出它们最可能的出价，而不仅仅是比最高价位高)。&lt;br /&gt;&lt;br /&gt;这种方法的基本操作如下：&lt;br /&gt;&lt;br /&gt;1.Alice向Bob发送出一串光子，所有这些光子都具有相同的偏振方式。&lt;br /&gt;2.Bob接收到这些光子，随机地改变他的偏振方式，然后记录下结果。&lt;br /&gt;3.当Bob的偏振方式和Alice的相同时，通过告知他他所见的1和0的形式，Alice能够向Bob证明她所发出的信息。&lt;br /&gt;&lt;br /&gt;这个系统的缺点是，Alice能够通过创建成对的光子而只向Bob发送一个来进行作弊。这些配对的光子有着奇怪的量子特性，无论它们分开多远，对一个的观察将会影响到令一个在接收者面前的样子。Alice可以通过修改她手中的副本来改变Bob的光子。研究者们已经发现这个问题一段时间了，而 Mayor 最近证明了，这是所有量子比特系统的一个普遍缺点。&lt;br /&gt;&lt;br /&gt;6.当今进展及未来展望&lt;br /&gt;最近，在“流体计算”技术方面由Dr.Gershenfield和Dr.chuang(Los Alamos国家实验室，新墨西哥州)领导的工作给予量子计算一个有前景的未来。事实上，Dr.Gershenfield相信，如果现在进步的速度持续下去的话，在不到10年的时间内，量子联合处理器将会变成现实。其它技术，例如量子点，当我们的技术进步后，可能会产生出类似的结果。而乐观者指出，现在研究人员所试验的问题看起来像是技术问题而不是根本性问题。&lt;br /&gt;尚未解决，并且许多人，包括IBM公司托马斯.沃森研究中心的Rolf Landauer，认为量子计算机不太可能发展超过10-量比系统(如上所述)，因为脱散性使它们过于脆弱以至于不实用。&lt;br /&gt;&lt;br /&gt;量子通讯方面的研究人员已经享受了很大程度上的成功。部分涉及到的计算机已经能够在大约10公路的距离上进行安全的通讯。根据发展这些线路的花费以及现存的对它们的需求，量子通讯将会有一个强大的未来。&lt;br /&gt;&lt;br /&gt;7.结论&lt;br /&gt;随着传统计算机渐渐接近它们的极限，量子计算机保证了给予一种新的计算能力水平。随着量子计算机的到来，一种结合了奇特的量子机械效应的，并将每种自然物体看做某种量子计算机的，全新的计算理论诞生了。因此，量子计算机具有模拟任何限定的自然系统的理论能力，并且掌握着制造一台人工智能计算机的关键。量子计算机通过大量的并行领域计算的能力，使它具有了快速计算许多传统计算机实际永远无法解决的任务的能力。这种能力仅仅在使用正确的算法时才能显现出来，然而这种算法是极其难以表达出来的。有些算法已经开发出来了，它们在密码使用系统领域有着巨大的应用。这是因为它们能使最常用的密码技术在几秒钟的时间内被破解掉。讽刺的是，量子计算和量子通讯的无旋转性，允许信息发送而使窃听者无法不被发现的窃听。 至少到现在，密码系统领域还是安全的，因为量子计算机被证明难以实现。它们强大的特别之处，它们对于量子机械的依赖，同时也使它们变得非常脆弱。即使最成功的试验也只能将1和1加在一起。没有人能够断言研究人员所尝试的问题能否被克服。一些人，例如Gershenfield博士，充满希望地认为它们能够做到；而同时，另外一些人相信量子计算机将会永远是脆弱而无法应用的。&lt;br /&gt;&lt;br /&gt;8.术语表&lt;br /&gt;连贯性 用来描述稳定重合状态的术语 &lt;br /&gt;计算流体 一种可能的量子计算机，它的分子可以被用作量比。 &lt;br /&gt;脱散性 当一个量比稳定在它的状态之一 &lt;br /&gt;DES 数据加密标准 &lt;br /&gt;对角型 45度或135度的偏振方向 &lt;br /&gt;Grover的算法 一个检索数据库的算法，同时也可以用来破解DES &lt;br /&gt;NMR 核磁共振 &lt;br /&gt;偏振方向 一个光子偏振的方向 &lt;br /&gt;公钥加密 一种利用分解大数字的难度以防止破解的加密方法 &lt;br /&gt;量子比特任务 一种有缺陷的信息原文件校验方法 &lt;br /&gt;量比 一个量子比特，它能够同时处于0和1状态 &lt;br /&gt;量子并行状态&lt;br /&gt; 通过对量比进行操作，可以在一次计算中处理许多值 &lt;br /&gt;量子通讯 使用量子影响发送信息，使窃听者无法不被发现的偷听 &lt;br /&gt;量子计算机 一台具有利用量子并行影响能力的计算机 &lt;br /&gt;量子点 一个量比的可能应用 &lt;br /&gt;直线型&lt;br /&gt; 水平和垂直的偏振方向 &lt;br /&gt;Shor的算法 分解大数字的算法 &lt;br /&gt;Toffoli门 一个通用的非门&lt;br /&gt; &lt;br /&gt;VLSI 超大规模集成电路 &lt;br /&gt;&lt;br /&gt;9.参照表&lt;br /&gt;9.1书籍&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;9.2人物&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;9.3杂志文章&lt;br /&gt;The coffee cup super computer. Tom Standage, Telegraph Connected 3/6/97 咖啡杯充当计算机(Tom Standage, Telegraph Connected 3/6/97) 对于量子计算的一个非常简要的介绍 &lt;br /&gt;A quantum revolution for computing. Julian Brown, New Scientist 24/9/94 计算的量子革命(Julian Brown, New Scientist 24/9/94) 包括相当具体的量子计算历史和一个相对简单的对Shor算法的解释 &lt;br /&gt;The best computer in all possible worlds. Tim Folger, Discover 1/10/95 所有可能领域中最好的计算机，(Tim Folger, Discover 1/10/95) 对于量子计算进步的长但是可理解的说明 &lt;br /&gt;Two-bit heroes - Computing with quanta. The Economist Volume 338 Issue 7948 两比特英雄--量子计算(The Economist Volume 338 Issue 7948) 一个量子计算的浅显介绍 &lt;br /&gt;Cue the qubits: Quantum computing - How to make a quantum computer. The Economist Volume 342 Issue 8005 量比的提示：量子计算--如何制造量子计算机(The Economist Volume 342 Issue 8005) 关于量子计算的有益介绍 &lt;br /&gt;Wake up to Quantum Coffee. Howard Baker, New Scientist 15/3/97 意识到量子咖啡(Howard Baker, New Scientist 15/3/97) 一个关于相对成功的量子计算方面的流体计算技术的全面讨论 &lt;br /&gt;Demonstrate logic gates for quantum computing. Bertram Schwarzchild, Physics Today 1/3/96 为量子计算证明逻辑门(Bertram Schwarzchild, Physics Today 1/3/96) 由物理学家指导的关于量子逻辑门的报告 &lt;br /&gt;Quantum cheats will always win. Robert Pool, New Scientist 17/5/97 量子欺骗总能获胜(Robert Pool, New Scientist 17/5/97) 一篇详细设计了量子比特任务通讯方案的基本基础的短文 &lt;br /&gt;Future of quantum computing proves to be debatable. Christopher Monroe, Physics Today 1/11/96 量子计算的未来是具有争议的(Christopher Monroe, Physics Today 1/11/96) 现实地看待量子计算的可行性 &lt;br /&gt;Quantum computation. David P. DiVincenzo, Science 13/10/95 量子计算(DiVincenzo, Science 13/10/95) 一份关于量子计算的全面报道，不幸的是，文章淹没在物理符号中 &lt;br /&gt;Brewing a quantum computer in a coffee cup. D. Vergano, Science News 18/1/97 在咖啡杯中酿造量子计算机(D. Vergano, Science News 18/1/97) 关于量子计算方面的流体计算技术的简要介绍 &lt;br /&gt;Universal Quantum Simulators. Seth Lloyd, Science 23/8/96 通用量子模拟器(Seth Lloyd, Science 23/8/96) 对于量子计算机在模拟方面应用的深入观察 &lt;br /&gt;When silicon hits its limits. Tom Thompson, Byte 1/4/96 当硅达到它的极限(Tom Thompson, Byte 1/4/96) 这篇文章包括对量子计算机的概念和它的可能优势的介绍 &lt;br /&gt;Quantum computation. Artur Ekert, American Institute of Physics 1993 量子计算(Artur Ekert, American Institute of Physics 1993) 一份全面但是技术性的论文 &lt;br /&gt;Searching a quantum phone book. Gilles Brassard, Science Volume 275 31/1/97 搜索一个量子电话本(Gilles Brassard, Science Volume 275 31/1/97) 尽管有些浅显，但仍然是对Grover算法的良好解释 &lt;br /&gt;Quantum-quick Queries. Ivars Peterson, Science News Volume 150 31/8/96 快速量子的置疑(Ivars Peterson, Science News Volume 150 31/8/96) 对于Grover算法的良好快速介绍 &lt;br /&gt;Quantum code breaking. The Economist, Volume 331 30/4/94 量子密码破解(The Economist, Volume 331 30/4/94) 用外行术语解释的密码破解 &lt;br /&gt;Quantum computation. David Deutsch, Physics World, 1/6/92 量子计算(David Deutsch, Physics World, 1/6/92) 一份关于量子计算的全面而鼓舞人心的指导 &lt;br /&gt;Experimental quantum cryptography. C.H.Bennet, F.Bessette, G.Brassard, L.Salvail, J.Smolin 1/11/91 实验性的量子密码系统技术(C.H.Bennet, F.Bessette, G.Brassard, L.Salvail, J.Smolin 1/11/91) 实例深入分析量子密码系统技术 &lt;br /&gt;Quantum keys for keeping secrets. Artur Ekert, New Scientist Volume 137 16/1/93 保护秘密的量子关键(Artur Ekert, New Scientist Volume 137 16/1/93) 非常有用的对于量子通讯的分析 &lt;br /&gt;&lt;br /&gt;其它文章：&lt;br /&gt;Quantum Computation, Physics World, 1992, David Deutsch&lt;br /&gt;A quantum leap in secret communications. William Bown, New Scientist 30/1/93&lt;br /&gt;Tight Bounds on Quantum Searching, M. Boyer, G. Brassard, P. Hoyer, A. Tapp&lt;br /&gt;Quantum Cryptoanalysis introduction, Artur Ekert&lt;br /&gt;Weirdest Computer of All, The Economist, 28 Sept. 1996&lt;br /&gt;Is the universe a computer?. Julian Brown, New Scientist 14/6/1990&lt;br /&gt;It takes two to tangle - in the quantum world. Ben Stein, New Scientist, 28/9/96&lt;br /&gt;Quantum communication thwarts eavesdroppers. David Deutsch, New Scientist, 9/12/89&lt;br /&gt;Quantum leap in code cracking computers. Mark Ward, New Scientist, 23/12/95&lt;br /&gt;Quantum Code-breaking, The Economist, 30 Apr. 1994&lt;br /&gt;Physical Revue Letters. (Vol. 78 p3414). &lt;br /&gt;&lt;br /&gt;9.4网页&lt;br /&gt;The Kitchen Sink 量子计算（连接到量子计算领域） http://sps1.phys.vt.edu/~alandahl/&lt;br /&gt;quantum_computing.html &lt;br /&gt;加里福尼亚理工学院量子光学 一个试图解决脱散性问题的团体 http://www.cco.caltech.edu/~qoptics/ &lt;br /&gt;量子密码分析学--介绍 对于使用Shor算法分解的有益介绍 http://eve.physics.ox.ac.uk/QCresearch/&lt;br /&gt;cryptoanalysis/qc.html &lt;br /&gt;粒子束流物理实验室 量子计算的链接 http://vesta.physics.ucla.edu/~smolin/index.html &lt;br /&gt;大量自旋共旋量子计算 有关咖啡杯量子计算机的文章 http://feynman.stanford.edu/qcomp/NMRQC/home.html &lt;br /&gt;Iain Stewarts的主页 更多关于量子计算的链接 http://www.doc.ic.ac.uk/~ids/quantum_computing.html &lt;br /&gt;量子编码 通过Innsbruck组的量子通讯 http://www.sigmaxi.org/Amsci/issues/Sciobs96/Sciobs96-11Encoding.html" &lt;br /&gt;量子计算方面的技术论文 各种关于量子计算机方面的论文，大部分需要深入的知识以理解 http://feynman.stanford.edu/qcomp/artlist.html&lt;br /&gt;&lt;br /&gt;II.&lt;br /&gt;发信人: GaoHuo (横扫企鹅), 信区: TsinghuaCent&lt;br /&gt;标  题: Re: 清华应明生组新添PRL一篇&lt;br /&gt;发信站: 水木社区 (Sun Jan 27 16:44:24 2008), 站内&lt;br /&gt;&lt;br /&gt;应老师做的就是要在计算模型上有突破，说到工艺，那还是遥远的未来才会考虑的。我对这一行算是一知半解，都是基于以往的旧知识，瞎说几句，望作引玉之砖。&lt;br /&gt;&lt;br /&gt;为什么说要在计算模型上有突破，自从费因曼提出量子计算机的概念后，一直有人声称量子计算机的计算能力比经典计算机强，这是个事实，已经被Shor算法、Grover算法部分证明。但是量子计算机是不是比传统计算机更有效，即对那些NP完全问题是否存在多项式量子算法，这就不是简单的靠几个特殊问题的量子算法能搞定的，必须从理论基础上进行研究。传统计算机的数学模型是图灵机，用来表示算法、程序和符号行的变换，研究算法复杂度是必不可少的。要从根本上研究量子计算机的计算能力，自然的想法就是建立有别于经典图灵机的量子图灵机数学模型，并在这个基础上定义各种算法复杂类比如QP问题类什么的（类似P、NP问题），如果能证明NP∈QP，那一切就都结了，量子计算机的计算能力确实比传统计算机高一个档次。但我印象中没见到过，几个著名的量子算法，Shor是BQP，有出错几率，而且不知道大数分解是否属于P或者NP；Grover搜索算法并不是log(N)的量子算法。因此这个领域是有大量问题需要研究的，比如计算机系姚期智的博士孙晓明一个被资助的研究项目就是“量子计算复杂性与经典计算复杂性的关系”。&lt;br /&gt;&lt;br /&gt;关于量子并行性，量子计算机被认为有更强大的计算能力，是因为所谓的量子计算的并行性，因为量子计算的“输入”可以通过Hadmard变换很容易生成一个有2^n个组份的量子迭加态，在这个输入上的进行的任何幺正变化（量子计算）都是同时对2^n个输入进行，就是所谓的量子并行计算，不过这里有个大问题，就是如何把这2^n个计算结果读出来？怎么知道哪个是想要的结果（除非不依赖于这一过程）？于是就有了10年前的Grover算法，该算法提出后轰动一时，成为量子信息方面灌水的超级大坑，因为貌似可以因此证明所有经典的NP问题在量子计算机上“运行”时至少可以比经典计算机快得多，不过可惜的是它仍然不是多项式的。另外当年好多group（都是物理学家）甚至宣称他们找到了对Grover搜索算法的根本性提高，即无序数据库的多项式量子算法，不过后来都一一被人拍死。当然如果真能找到这样的算法，那么就真有NP∈QP，牛人们不妨继续吃这个螃蟹。&lt;br /&gt;&lt;br /&gt;再说到应老师。量子图灵机的概念最早1985年Deutsch就提出了，但是看起来很糙。后来很多物理学家都试图完善量子图灵机的定义，写了很多paper，不过我个人认为似乎都有个缺陷，就是他们都是在原来的图灵机模型上作简单的修补，把量子力学的态的性质传递给图灵机，这样虽然直观，但在这样的模型上进行文法、算法的研究基本是不可能的，不知道后来有何发展。另外就是引入量子自动机模型，这些Moore、Gudder等人都做过，效果如何本人就不知道了。应明生老师在国际上率先独创性提出基于量子逻辑也就是完备正交模格值（而不是传统的布尔代数）的自动机理论，并和弟子们在文法理论中作了一系列漂亮的工作（在国内反正是曲高和寡），他们也由此切入到本该物理学家研究的领域，即量子信息中的一些物理问题，因此就有了国内计算机系破天荒的3篇PRL。应老师做的这些理论模型，即使量子计算机今后不具备物理实现的可能（个人倾向于这一点），也是很有意义和启发性的，毕竟量子计算机带来了给出NP完全问题的多项式算法的可能性。&lt;br /&gt;&lt;br /&gt;八卦几句量子逻辑。其实量子逻辑的最初概念1936年始于冯诺伊曼，不过和量子计算风马牛不相及，当年是为了掺和量子力学的测量问题争论的。该问题当年令无数大物理学家争论不休，如今也有不少民科为之着迷。因为测量过程的随机、不可逆、非定域性等等，有一个学派（Modal Interpretation？）认为不能用建立在经典逻辑基础上的推理系统来对这个问题进行推理，必须根据量子力学的根基重建一套与“物理本质”相符的逻辑与推理系统，就是后来成型的量子逻辑，清华图书馆有几本80年代英国人写的书，就是关于这个的，其中有一本通过一系列引理定理建立了基于完备正交模格（如果我记的不错的话）的逻辑推理系统，书最后用这个讨论了贝尔不等式。后来该方向基本无人问津了，再后来不知道是不是巧合，为了研究量子计算，应老师又建立了完备正交模格值上的自动机理论，不过仔细想想这也是很自然的，量子计算机的物理实现就和测量、非定域性这些量子力学基本问题非常紧密联系，前后两者的研究方法出现一定相似性并不偶然。&lt;br /&gt;&lt;br /&gt;【 在 Wiltord (爱妮亿万年) 的大作中提到: 】&lt;br /&gt;: 量子计算机指的工艺上用量子代替现在的半导体？计算模型还需要改么？&lt;br /&gt;: 如果这样说来，量子计算机的贡献也不一定会大过计算模型吧，例如并行&lt;br /&gt;: 量子计算机的优点是什么？功耗更小，集成度更高，频率更高，还是别的？&lt;br /&gt;: ...................&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;&lt;br /&gt;※ 修改:·GaoHuo 于 Jan 27 17:03:29 修改本文·[FROM: 211.99.222.*]&lt;br /&gt;※ 来源:·水木社区 newsmth.net·[FROM: 211.99.222.*]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;III.&lt;br /&gt;◇◇新语丝(http://www.xys.org)(xys.dxiong.com)(xys.dropin.org)(xys-reader.org)◇◇&lt;br /&gt;&lt;br /&gt;　　说说北大王国文对潘建伟工作的评论——兼谈量子力学的定域性问题&lt;br /&gt;&lt;br /&gt;　　作者：polik&lt;br /&gt;&lt;br /&gt;　　1. 引子&lt;br /&gt;&lt;br /&gt;　　首先，王国文的文章根本是垃圾。要是一般人写的，权且当作民科难抑寂寞&lt;br /&gt;发泄一番，大可一笑了之。他的文章没人理睬，可能也是出于这个原因吧。由于&lt;br /&gt;署名北京大学物理学院，并非冒名，在网络上转载还颇热闹，polik就觉得有点&lt;br /&gt;过意不去。诚然，北大水平与王国文属于同一级别，并无必要为捍卫北大声誉浪&lt;br /&gt;费时间，北大的声誉是否大于零，本人及同道一向强烈持疑。但为公众能得到正&lt;br /&gt;确的科普起见，花点时间点批一下，免得有人说学术界的人普遍缺德，见妖言惑&lt;br /&gt;众而不喝止。何况这是他第二次拿这种东西来占新语丝的版面争读者眼球了。对&lt;br /&gt;这种abuse自由媒体和开明版主的人发慈悲就是对老实百姓的残忍。&lt;br /&gt;&lt;br /&gt;　　更不是替潘建伟来抱不平。潘近年在国际上，而不只是国内，出了一些风头，&lt;br /&gt;实惠虚名都赚了不少，除不值得同情以外，其知名度和公众人物身份使得他有接&lt;br /&gt;受公众质问的义务。其次，他的东西并非如他自己/他前老板/国际物理通讯兵们&lt;br /&gt;所吹的那样美好和神奇。加之潘本人大话不停，牛皮甚多，发烧友一堆，此时忠&lt;br /&gt;告一下对他本人及其团队，刚入道的研究生，还有那些非替老百姓管钱不可的官&lt;br /&gt;僚都有好处。但王国文这种不伦不类的文章一不符合学术界惯例（你有好的观点，&lt;br /&gt;有数不清的杂志欢迎你投稿，潘在Physical Review Letters上发文章，你有异&lt;br /&gt;见，PRL绝对欢迎你comment！），二是根本不着边际，徒然给人故意搅局或当托&lt;br /&gt;儿的联想，增加某些专业人员对潘和前老板及其好友们的工作的进一步追捧。&lt;br /&gt;&lt;br /&gt;　　2. 王国文的文章为何是垃圾？&lt;br /&gt;&lt;br /&gt;　　一个真正有创意的观点，写成一篇正式学术文章以后，一般都会舍不得投IF&lt;br /&gt;不够高的杂志，更不会轻易送到科普媒体上去"发表"。可以想像，王其实明白自&lt;br /&gt;己的东西是个笑料。当然，王可能不食人间烟火，跟隐士Perelman一样，不发杂&lt;br /&gt;志文章。所以，在这里权且抬举抬举他，把他的文章当成正式工作comment一下。&lt;br /&gt;&lt;br /&gt;　　王文的第一个批评，也是其主旨，就是质疑三光子纠缠态是否真的纠缠态。&lt;br /&gt;理由是那些光子的态是"事后诸葛"式的重建的。这样的作法根本不是潘的原创，&lt;br /&gt;至少已有10几年的历史了。虽然最初有些人对这种方法强烈反对，但对它的质疑&lt;br /&gt;已经遭到了彻底的回驳。此事已经尘埃落定，绝非王文所称的"未见有人能讲清&lt;br /&gt;楚它的物理机制"。Science 杂志还曾专门请人写了篇高级科普见证，详见&lt;br /&gt;Science 2005, 307卷,第875-879页。简而言之，事实上，经过稍许澄清即可以&lt;br /&gt;得知，传统上对干涉条纹的指认或归属与这种"事后诸葛"式的重建并无本质差异。&lt;br /&gt;现在对这样的纠缠态已经司空见惯。早于潘发表的文章数以十计，这个技巧根本&lt;br /&gt;不是"潘建伟研究组的工作"的核心，而且也不是潘的前老板Zeilinger提出的。&lt;br /&gt;王没有了解这些基本知识，瞎批一通。&lt;br /&gt;&lt;br /&gt;　　王一方面通过否定量子力学目前容许的"非定域特征"来批评"潘建伟研究组&lt;br /&gt;的工作"可能建立在脆弱的学理上，另一方面他又毫不顾忌地引入无丝毫实验证&lt;br /&gt;据更为离奇的所谓"准空态"来解释现有的实验观察，其大无畏精神必令堂吉柯德&lt;br /&gt;自叹弗如。退一万步，假设真的有他说的"准空态"，要解释EPR关联，那也无法&lt;br /&gt;摆脱超距作用，只是换成子虚乌有的"准空态"与所谓"非空态"的超距影响而已。&lt;br /&gt;这会是个幽灵"潜波"加隐变量再加超距作用的三重魔怪。而且，显然，这种超距&lt;br /&gt;作用会有真正的灾难性，相对论必然就此咽气，而量子力学容许的超距作用因受&lt;br /&gt;随机性的保护却不产生灾难。不知道他到底要捍卫什么？不信的话，王不妨把他&lt;br /&gt;的观点写成学术文章投到中国的"物理学报"或其他任何一家需要审稿的杂志，保&lt;br /&gt;证退稿。&lt;br /&gt;&lt;br /&gt;　　王声称"声名狼藉的（infamous）波函数坍缩假设在量子物理中可能是完全&lt;br /&gt;多余的。"完全是民科式的武断。波函数崩塌有人怀疑，解释崩塌的理论也好几&lt;br /&gt;个，但绝不是声名狼藉。恰恰相反，事实是，波函数崩塌依然是量子力学解释测&lt;br /&gt;量结果必不可少的假设。虽然现在对崩塌过程的细节描述上还有一些问题没有得&lt;br /&gt;到完全满意的解决，但崩塌本身作为一个事实已经无人怀疑（民科和疑似民科除&lt;br /&gt;外）。&lt;br /&gt;&lt;br /&gt;　　王所引用的那些质疑量子力学正统解释的人和他们的话，都是边缘人物或者&lt;br /&gt;极端少数观点。不是说边缘人物都有问题，但决不是边缘人物的话就是对的。他&lt;br /&gt;引用的一些人根本就是一些熟知的民科水平的大嘴巴学者。再如，他引用这些国&lt;br /&gt;际民科的话说:"贝尔不等式实验检验的违反只表明经典统计法不适用于推导量子&lt;br /&gt;力学的预言"以及德布罗意基金会前主席洛察克（G. Lochak）说"依我之见，贝&lt;br /&gt;尔不等式的实验违反无关于所谓的'非定域性'或'非分离性'。这违反只不过表明&lt;br /&gt;量子几率不是经典几率!"请问：能否给出所谓"量子概率"的定义？如何用它理解&lt;br /&gt;Bell定理？再说，这些话与王推崇的"准空态"和"潜波"有何关连？&lt;br /&gt;&lt;br /&gt;　　对该领域稍有基础的人不难看出，王与潘的学术水平之落差是超距的，根本&lt;br /&gt;不是一个层次。王如果真正关心量子光学或量子计算，应该先好好复习一下量子&lt;br /&gt;力学，读几篇像样的文献，再作打算，而不是在读了一些国内国际的民科作品以&lt;br /&gt;后就乱发议论。用一篇充满学术漏洞和常识错误的文章去评论一篇正式发表的文&lt;br /&gt;章，根本就是变相替人家抬轿吆喝。例如，王把 J. A. Wheeler说成是诺贝尔奖&lt;br /&gt;得主，把德布罗依的"空波"和"从体"说成是解救非定域困难的药方等等，这类小&lt;br /&gt;儿科错误一犯，北大水平就原形毕露。看到这样的批评文章，我不得不怀疑作者&lt;br /&gt;是志愿替潘建伟当沙袋的。&lt;br /&gt;&lt;br /&gt;　　3. 对潘及其前老板工作的评价&lt;br /&gt;&lt;br /&gt;　　刚才我查到，潘建伟因为曾把国外成果谎报成"在中国本土完成"并诡称全职&lt;br /&gt;回科大等丑事被新语丝立此存照，但没有人否认他的研究成绩。而且polik认为，&lt;br /&gt;潘犯那些丑事很可能是要配合科大当局急功好利到上面表功蒙钱，因此这里我不&lt;br /&gt;考虑"德"这个因素，纯粹从学术角度评论。&lt;br /&gt;&lt;br /&gt;　　客观地讲，潘是个有实力的学者，甚至还是少有的国际物理新星。他的文章&lt;br /&gt;之篇数，影响因子以及引用次数，绝对盖过全部中科院院士。但是，综观潘的全&lt;br /&gt;部工作，主要的学术思想和指导哲学都是潘的前老板Anton Zeilinger的。潘是&lt;br /&gt;一个出色的学生，理论水平和实验技术皆令人称道，对其前老板某些方面的工作&lt;br /&gt;有所发扬光大。但是，把将光子纠缠用于量子计算说成是"潘建伟研究组的工作"，&lt;br /&gt;潘起码无法向Zeilinger交代。另外，潘与Zeilinger恐怕会就多光子纠缠的优先&lt;br /&gt;权问题弄出是非，因为我看到 Zeilinger不只一次讲是他先制备出五、六光子纠&lt;br /&gt;缠，而潘也做了类似的声称。&lt;br /&gt;&lt;br /&gt;　　了解此领域的人知道，Zeilinger的工作不只涉及到这里谈到的量子计算，&lt;br /&gt;他更早在量子光学，非破坏测量，GHZ纠缠态等方面的工作就使其名声大噪。但&lt;br /&gt;圈内对他的工作评价远远没有媒体描述的那样高，他的工作基本上就是反覆表演&lt;br /&gt;和宣称"看！量子力学又被证明是对的！"，虽然不少在Nature等明星杂志出现甚&lt;br /&gt;至封面推荐，其教育意义远大于学术价值。靠这种工作拿诺奖，从诺奖历史看，&lt;br /&gt;行情真的很不看好，只能恨诺奖既不是看IF，更不是数篇数。这里顺便指出，&lt;br /&gt;Zeilinger教授学术水平不低，其公关水平也很高，对操弄媒体、宗教（如与回&lt;br /&gt;教佛教"打得火热"，请达赖喇嘛到实验室访问演说，参加达赖的宗教─科学对话&lt;br /&gt;活动之类）、政客、以及同行来增加自己知名度非常在行。他的工作多次登上"&lt;br /&gt;年度物理进展"，"世界物理学近50年重大成果"等吓人的学术新闻榜，与他的公&lt;br /&gt;关水平不无关系。如此招摇、卖力公关以致不诸形式的科学家，在史上是绝对少&lt;br /&gt;见的。当我看到他对达赖喇嘛写的书"单原子中的宇宙"推崇备至时，觉得他与那&lt;br /&gt;个曾经证明亩产万斤粮、宣称人体科学是高技术平方的力学专家有同样的投机嗅&lt;br /&gt;觉能力。&lt;br /&gt;&lt;br /&gt;　　潘的工作也已经几次进入当年国际物理进展新闻，虽然或多或少与&lt;br /&gt;Zeilinger有关联，但对一个年轻科学家，且来自一个科技不发达的官本位封建&lt;br /&gt;国家，应该说这是很了不起的。但是研究结果上新闻与真正的学术价值，尤其是&lt;br /&gt;经得起时间考验的长久价值，可以说根本不是一回事。风云一时最后以昙花一现&lt;br /&gt;方式草草离场的研究方向和领域在历史上数不胜数，层出不穷。物理领域最近的&lt;br /&gt;例子就有混沌、分形、几何相位、高温超导理论、复杂性理论、数不清的宇宙学&lt;br /&gt;理论，甚至弦论等等，其他领域如生物医学、经济学应该更多。量子计算领域只&lt;br /&gt;是更糟一点，呈现了上述领域的所有病态特征而尚未显示出一点起码的成果。那&lt;br /&gt;些声称是"量子线路"、"量子计算机"的东西无一不是一些古旧实验的花哨叫法而&lt;br /&gt;已。冷静看一下潘的那些上新闻的成果，最后有能流传下去的吗？下面讲讲量子&lt;br /&gt;计算的潜在问题和巨大困难，有助于对潘的工作和整个量子信息领域有一番整体&lt;br /&gt;的审视。潘或其学生如果读到这篇文章，请相信 polik，绝对是为你们好。&lt;br /&gt;&lt;br /&gt;　　首先，虽然现在的量子力学"非定域性"相当安全，不会产生灾难，更有一大&lt;br /&gt;票人甚至头面人物认定这种"非定域性 "是量子力学（或微观世界）的根本特征，&lt;br /&gt;是待开发的巨大资源，但对量子力学到底是否非定域的争论还在进行之中。我们&lt;br /&gt;知道，EPR的解释并不需要超距作用，纠缠态也不意味超距作用，格林函数不包&lt;br /&gt;含任何类空贡献。种种迹象表明，量子力学的"非定域性"是对量子力学理解或解&lt;br /&gt;释层面上的问题，是形而上的 metaphysics，对技术部分不会有影响，因此所谓&lt;br /&gt;的"非定域资源"很可能是一种幻想。但Zeilinger深信超距作用的真实性，已经&lt;br /&gt;影响了相当多的学者和学生，包括潘。他的这种信仰，与其说是立场坚定，更像&lt;br /&gt;赌徒作风，因为理性和实证的成分很少。这无疑也给他在学术界招来怀疑的眼光&lt;br /&gt;甚至否定的评论。像Cornell的物理学家David Mermin就直指Zeilinger的一些工&lt;br /&gt;作"too good to be true"，绝对是负面的评价。因此，非定域性是否真的可以&lt;br /&gt;当作未来的计算资源值得大大怀疑。严格地讲，基于纠缠态的量子计算器的存在&lt;br /&gt;性证明并未完成。一旦这个问题是否定的回答，整个基于纠缠的量子计算的学理&lt;br /&gt;平台轰然崩塌，那些"年度物理进展"，"世界物理学近50年重大成果"等顿时灰飞&lt;br /&gt;烟灭，付诸笑谈。这绝非危言耸听。&lt;br /&gt;&lt;br /&gt;　　量子计算的另一个重大难点甚至致命困难是可放大性(scalability)问题，&lt;br /&gt;即能否做到实用计算要求的至少上百个量子比特而不只是少数几个量子比特，它&lt;br /&gt;是计算机处理器的核心问题。这是目前所有量子计算方案共同面临的严重困难。&lt;br /&gt;远远不是当年建立电子计算机时那样的可放大性问题。尽管不排除最终可能会找&lt;br /&gt;到出路，但其难度非同一般，即算有解，获得解决的时间也将是非常漫长的，已&lt;br /&gt;是圈内清醒人的共识。不讲清这些，只听单方面的乐观意见，很容易被误导。潘&lt;br /&gt;和国际国内上一些人出于可以理解的私心，过分强调量子计算尤其是基于光子的&lt;br /&gt;量子计算的优势和前景，甚至许以几年以后你就可以订购量子电脑的画饼，做了&lt;br /&gt;一些误导公众，学术界和官员的宣传。例如，用Shor演算法作质因子分解15＝5&lt;br /&gt;×3的演示实验，早在6年多前就有人发表。潘组用光子做出此项工作，确实是不&lt;br /&gt;错的进展。但稍微想一想，三光子或五光子实验已是困难重重，纠缠脆弱无比，&lt;br /&gt;要做到比如说十光子纠缠此路可通？何况十光子纠缠与几百个光子纠缠完全不是&lt;br /&gt;同一类型的难度。甚至有人声称已经证明，基于光子纠缠的量子计算机原则上没&lt;br /&gt;有可放大性。欧美杂志或媒体对潘几件工作的夸颂，猛一看了不得，但仔细看看，&lt;br /&gt;那些吹喇叭的都是些鼓吹量子计算机近在眼前的要钱激进分子，有些更是潘的国&lt;br /&gt;际合作者们或Zeilinger的朋友。那些新闻背后的最主要目的是借此写申请书时&lt;br /&gt;可以向各国政府索要更多的支持。从这一点看，Zeilinger风格不用担心失传。&lt;br /&gt;不过，也有人说，Zeilinger及其弟子们每这么样来一次，其同行评价就降三分。&lt;br /&gt;&lt;br /&gt;　　由于Zeilinger之名气，故学生闲谈和媒体上有他可能拿诺奖的传言，但由&lt;br /&gt;于上述原因，行家并不认为他有多少可能性。此外，他更早的学生和合作者中，&lt;br /&gt;胜过潘或与潘可比者人数众多。因此，即算pigs fly，诺贝尔奖光顾此领域，也&lt;br /&gt;断然不会落到潘的头上。刚才看到潘准备在万里长城上作量子密码实验的消息，&lt;br /&gt;不禁哑然，只怕是他成也Zeilinger，败也Zeilinger。如此照搬照抄，重复&lt;br /&gt;Zeilinger在多瑙河上作的公关表演，与东施效颦何异？潘或其学生如果真有志&lt;br /&gt;于诺奖，不妨冷静地想想，要不要在基于光子纠缠的量子计算这一棵树上吊死？&lt;br /&gt;或永远紧跟Zeilinger走遍天涯而无怨无悔？还是趁早另辟蹊径，以遂良愿呢？&lt;br /&gt;有志在量子光学和量子计算领域做出重大成果者，对Zeilinger及其合作者的工&lt;br /&gt;作或宣导，我也劝你还是谨慎一点为好。&lt;br /&gt;&lt;br /&gt;　　polik感谢HYC，KG，YYL，XZ的讨论和批评意见&lt;br /&gt;&lt;br /&gt;(XYS20080127)&lt;br /&gt;&lt;br /&gt;◇◇新语丝(http://www.xys.org)(xys.dxiong.com)(xys.dropin.org)(xys-reader.org)◇◇&lt;br /&gt;&lt;br /&gt;Re: 评潘建伟研究组的量子计算机&lt;br /&gt;由 星空浩淼 于 2008年1月28日 00:56 &lt;br /&gt;&lt;br /&gt;polik的这篇反驳文章如果就事论事，只从学术角度进行辩驳，倒是值得尊敬的。可惜文章里带有骂街的味道。我赞同他的主要观点，但是在我看来，他在这篇文章里犯了以下几个错误：&lt;br /&gt;1）polik把“非局域性”直接等价于“超距作用”，在我看来这是明显错误的理解；&lt;br /&gt;2）并非所有格林函数（Feynman传播子）不包含任何类空贡献，只能说场算子之间的协变对易子在类空间隔下严格为零。粒子的类空传播事实上是存在的，只是这种超光速行为由于正反粒子对称性而不产生因果悖论——正因为正反粒子对称性，才使得场算子之间的协变对易子在类空间隔下严格为零，从而一个测量行为，不能类空地影响另一个测量行为。&lt;br /&gt;3）不管格林函数是否包含类空贡献，它所能反应出来的问题，跟量子力学中所谈到的非局域性特征是两码事。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-117005589347754993?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/117005589347754993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/117005589347754993'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2007/01/some-notes-on-quantum-machine-1.html' title='Some notes on quantum machine - 1'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-116919409546817018</id><published>2007-01-01T00:05:00.000-08:00</published><updated>2007-01-19T00:08:15.790-08:00</updated><title type='text'>古诗十九首之四</title><content type='html'>今日良宴会，欢乐难具陈。&lt;br /&gt;弹筝奋逸响，新声妙入神。&lt;br /&gt;令德唱高言，识曲听其真。&lt;br /&gt;齐心同所愿，含意俱未申。&lt;br /&gt;人生寄一世，奄忽若飙尘。&lt;br /&gt;何不策高足，先据要路津。&lt;br /&gt;无为守贫贱，坎轲长苦辛。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-116919409546817018?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/116919409546817018'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/116919409546817018'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2007/01/blog-post.html' title='古诗十九首之四'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-113769891751814381</id><published>2006-12-31T11:28:00.000-08:00</published><updated>2006-10-16T01:15:50.566-07:00</updated><title type='text'>Category of TeleStar's Notes in 2006</title><content type='html'>&lt;ul&gt;&lt;li&gt;January - Tex/Latex Related &lt;/li&gt;&lt;li&gt;February - Ajax Related&lt;/li&gt;&lt;li&gt;March - Collection of Advices&lt;/li&gt;&lt;li&gt;April - Search Engine Related&lt;/li&gt;&lt;li&gt;May - &lt;/li&gt;&lt;li&gt;June - DotNet&lt;/li&gt;&lt;li&gt;July - &lt;/li&gt;&lt;li&gt;August - &lt;/li&gt;&lt;li&gt;September - &lt;/li&gt;&lt;li&gt;Octobor - &lt;/li&gt;&lt;li&gt;November - &lt;/li&gt;&lt;li&gt;December - C++/C#&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-113769891751814381?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/113769891751814381'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/113769891751814381'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2006/12/category-of-telestars-notes-in-2006.html' title='Category of TeleStar&apos;s Notes in 2006'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-110263943949619760</id><published>2006-12-26T16:40:00.000-08:00</published><updated>2008-01-15T01:24:43.037-08:00</updated><title type='text'>ProcessThread and Thread in C#</title><content type='html'>稍微整理了一下以前的一些相关笔记&lt;br /&gt;&lt;br /&gt;1.&lt;br /&gt;首先看看MSDN的标准注释&lt;br /&gt;&lt;br /&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/aptnthrd_8po3.asp&lt;br /&gt;&lt;br /&gt;A process is a collection of virtual memory space, code, data, and system resources. A thread is code that is to be serially executed within a process. A processor executes threads, not processes, so each 32-bit application has at least one process, and a process always has at least one thread of execution, known as the primary thread. A process can have multiple threads in addition to the primary thread. Prior to the introduction of multiple threads of execution, applications were all designed to run on a single thread of execution. &lt;br /&gt;&lt;br /&gt;Processes communicate with one another through messages, using Microsoft's Remote Procedure Call (RPC) technology to pass information to one another. There is no difference to the caller between a call coming from a process on a remote machine and a call coming from another process on the same machine.&lt;br /&gt;&lt;br /&gt;When a thread begins to execute, it continues until it is killed or until it is interrupted by a thread with higher priority (by a user action or the kernel's thread scheduler). Each thread can run separate sections of code, or multiple threads can execute the same section of code. Threads executing the same block of code maintain separate stacks. Each thread in a process shares that process's global variables and resources.&lt;br /&gt;&lt;br /&gt;The thread scheduler determines when and how often to execute a thread, according to a combination of the process's priority class attribute and the thread's base priority. You set a process's priority class attribute by calling the Win32&amp;reg; function SetPriorityClass, and you set a thread's base priority with a call to SetThreadPriority.&lt;br /&gt;&lt;br /&gt;Multithreaded applications must avoid two threading problems: deadlocks and races. A deadlock occurs when each thread is waiting for the other to do something. The COM call control helps prevent deadlocks in calls between objects. A race condition occurs when one thread finishes before another on which it depends, causing the former to use a bogus value because the latter has not yet supplied a valid one. COM supplies some functions specifically designed to help avoid race conditions in out-of-process servers. (See Out-of-Process Server Implementation Helpers.)&lt;br /&gt;&lt;br /&gt;另外&lt;br /&gt;&lt;br /&gt;In most multithreading operating systems, a process gets its own memory address space; a thread doesn't. Threads typically share the heap belonging to their parent process. For instance, a JVM runs in a single process in the host O/S. Threads in the JVM share the heap belonging to that process; that's why several threads may access the same object. Typically, even though they share a common heap, threads have their own stack space. This is how one thread's invocation of a method is kept separate from another's. This is all a gross oversimplification, but it's accurate enough at a high level. Lots of details differ between operating systems.&lt;br /&gt;&lt;br /&gt;2.&lt;br /&gt;好，现在是我们讨论的问题，如何计算Process和Thread所花费的时间（主要是比较算法的优劣用）&lt;br /&gt;&lt;br /&gt;C#中的Process属于namespace System.Diagnostics，从rotor的代码来看，它就是系统process的一个简单薄层封装。&lt;br /&gt;http://www.123aspx.com/rotor/RotorSrc.aspx?rot=41538&lt;br /&gt;&lt;br /&gt;所以我们可以直接用UserProcessorTime和PrivilegedProcessorTime两个属性来检测Process所花时间&lt;br /&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemdiagnosticsprocessclassprivilegedprocessortimetopic.asp&lt;br /&gt;&lt;br /&gt;其实也就是系统的GetProcessTimes函数的应用，MFC可参见&lt;br /&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getprocesstimes.asp&lt;br /&gt;http://www.codeproject.com/threads/getprocesstimes.asp&lt;br /&gt;&lt;br /&gt;C#中的ProcessThread属于namespace System.Diagnostics，不过没有代码可看，估计也是一个系统thread的简单薄层封装。所以我们还有如下的属性可以使用&lt;br /&gt;&lt;br /&gt;System.Diagnostics.ProcessThread.PrivilegedProcessorTime&lt;br /&gt;System.Diagnostics.ProcessThread.TotalProcessorTime&lt;br /&gt;System.Diagnostics.ProcessThread.UserProcessorTime&lt;br /&gt;参见&lt;br /&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfSystemDiagnosticsProcessThreadPropertiesTopic.asp&lt;br /&gt;&lt;br /&gt;其实也就是系统的thread的GetThreadTimes函数，MFC应用参见&lt;br /&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/getthreadtimes.asp&lt;br /&gt;&lt;br /&gt;可是我们一般都是从namespace System.Threading派生thread来用，这个thread是DotNet新创建的类，完全没有任何与计时有关的东西，所以不能通过比较每个thread的实际花费时间来分析算法的瓶颈。&lt;br /&gt;&lt;br /&gt;那么虚拟机到底是怎么调度threadpool里面的thread的，难道它能不考虑每个thread花费的时间吗？我在网上翻到Chris Brumme大牛的答案是这样的&lt;br /&gt;&lt;br /&gt;Threads, fibers, stacks &amp; address space&lt;br /&gt;by Chris Brumme &lt;br /&gt;from http://blogs.msdn.com/cbrumme/archive/2003/04/15/51351.aspx&lt;br /&gt;&lt;br /&gt;Every so often, someone tries to navigate from a managed System.Threading.Thread object to the corresponding ThreadId used by the operating system.&lt;br /&gt;&lt;br /&gt;System.Diagnostic.ProcessThread exposes the Windows notion of threads.  In other words, the OS threads active in the OS process.&lt;br /&gt;&lt;br /&gt;System.Threading.Thread exposes the CLR’s notion of threads.  These are logical managed threads, which may not have a strict correspondence to the OS threads.  For example, if you create a new managed thread but don’t start it, there is no OS thread corresponding to it.  The same is true if the thread stops running – the managed object might be GC-reachable, but the OS thread is long gone.  Along the same lines, an OS thread might not have executed any managed code yet.  When this is the case, there is no corresponding managed Thread object.&lt;br /&gt;&lt;br /&gt;A more serious mismatch between OS threads and managed threads occurs when the CLR is driven by a host which handles threading explicitly.  Even in V1 of the CLR, our hosting interfaces reveal primitive support for fiber scheduling.  Specifically, look at ICorRuntimeHost’s LogicalThreadState methods.  But please don’t use those APIs – it turns out that they are inadequate for industrial-strength fiber support.  We’re working to get them where they need to be.&lt;br /&gt;&lt;br /&gt;In a future CLR, a host will be able to drive us to map managed threads to host fibers, rather than to OS threads.  The CLR cooperates with the host’s fiber scheduler in such a way that many managed threads are multiplexed to a single OS thread, and so that the OS thread chosen for a particular managed thread may change over time.&lt;br /&gt;&lt;br /&gt;When your managed code executes in such an environment, you will be glad that you didn’t confuse the notions of managed thread and OS thread.&lt;br /&gt;&lt;br /&gt;When you are running on Windows, one key to good performance is to minimize the number of OS threads.  Ideally, the number of OS threads is the same as the number of CPUs – or a small multiple thereof.  But you may have to turn your application design on its head to achieve this.  It’s so much more convenient to have a large number of (logical) threads, so you can keep the state associated with each task on a stack.&lt;br /&gt;&lt;br /&gt;When faced with this dilemma, developers sometimes pick fibers as the solution.  They can keep a large number of cooperatively scheduled light-weight fibers around, matching the number of server requests in flight.  But at any one time only a small number of these fibers are actively scheduled on OS threads, so Windows can still perform well.&lt;br /&gt;&lt;br /&gt;SQL Server supports fibers for this very reason.&lt;br /&gt;&lt;br /&gt;However, it's hard to imagine that fibers are worth the incredible pain in any but the most extreme cases.  If you already have a fiber-based system that wants to run managed code, or if you’re like SQL Server and must squeeze that last 10% from a machine with lots of CPUs, then the hosting interfaces will give you a way to do this.  But if you are thinking of switching to fibers because you want lots of threads in your process, the work involved is enormous and the gain is slight.&lt;br /&gt;&lt;br /&gt;Instead, consider techniques where you might keep most of your threads blocked.  You can release some of those threads based on CPU utilization dropping, and then use various application-specific techniques to get them to re-block if you find you have released too many.  This kind of approach avoids the rocket science of non-preemptive scheduling, while still allowing you to have a larger number of threads than could otherwise be efficiently scheduled by the OS.&lt;br /&gt;&lt;br /&gt;Of course, the very best approach is to just have fewer threads.  If you schedule your work against the thread pool, we'll try to achieve this on your behalf.  Our threadpool will pay attention to CPU utilization, managed blocking, garbage collections, queue lengths and other factors – then make sensible dynamic decisions about how many work items to execute concurrently.  If that’s what you need, stay away from fibers.&lt;br /&gt;&lt;br /&gt;If you have lots of threads or fibers, you may have to reduce your default stack size.  On Windows, applications get 2 GB of address space.  With a default stack size of 1 MB, you will run out of user address space just before 2000 threads.  Clearly that’s an absurd number of threads.  But it’s still the case that with a high number of threads, address space can quickly become a scarce resource.&lt;br /&gt;&lt;br /&gt;On old versions of Windows, you controlled the stack sizes of all the threads in a process by bashing a value in the executable image.  Starting with Windows XP and Windows Server 2003, you can control it on a per-thread basis.  However, this isn’t exposed directly because:&lt;br /&gt;&lt;br /&gt;1)         It is a recent addition to Windows.&lt;br /&gt;&lt;br /&gt;2)         It’s not a high priority for non-EXE’s to control their stack reservation, since there are generally few threads and lots of address space.&lt;br /&gt;&lt;br /&gt;3)         There is a work-around.&lt;br /&gt;&lt;br /&gt;The work-around is to PInvoke to CreateThread, passing a Delegate to a managed method as your LPTHREAD_START_ROUTINE.  Be sure to specify STACK_SIZE_PARAM_IS_A_RESERVATION in the CreationFlags.  This is clumsy compared to calling Thread.Start(), but it works. &lt;br /&gt;&lt;br /&gt;Incidentally, there’s another way to deal with the scarce resource of 2 GB of user address space per process.  You can boot the operating system with the /3GB switch and – starting with the version of the CLR we just released – any managed processes marked with IMAGE_FILE_LARGE_ADDRESS_AWARE can now take advantage of the increased user address space.  Be aware that stealing all that address space from the kernel carries some real costs.  You shouldn’t be running your process with 3 GB of user space unless you really need to.&lt;br /&gt;&lt;br /&gt;The one piece of guidance from all of the above is to reduce the number of threads in your process by leveraging the threadpool.  Even client applications should consider this, so they can work well in Terminal Server scenarios where a single machine supports many attached clients.&lt;br /&gt;&lt;br /&gt;flier说得很对，Chris Brumme的blog是不能不看的。&lt;br /&gt;&lt;br /&gt;3.&lt;br /&gt;BackgroundWorker&lt;br /&gt;&lt;br /&gt;from http://www.cnblogs.com/yizhu2000/archive/2007/10/19/929930.html&lt;br /&gt;&lt;br /&gt;这篇我们来介绍一下异步编程的经典模式和微软对其的实现&lt;br /&gt;&lt;br /&gt;微软推荐的异步操作模型是事件模型,也即用子线程通过事件来通知调用者自己的工作状态,也就是设计模式中的observer模式,也可以看成是上文中线程类的扩展,最后实现后调用效果类似于&lt;br /&gt;&lt;br /&gt;MyThread thread=new MyThread()&lt;br /&gt;&lt;br /&gt;thread.Work+=new ThreadWork(Calculate)&lt;br /&gt;&lt;br /&gt;thread.WorkComplete+=new WorkComplete(DisplayResult)&lt;br /&gt;&lt;br /&gt;Calculate(object sender, EventArgs e)){&lt;br /&gt;&lt;br /&gt;....&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;DisplayResult(object sender, EventArgs e)){&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;这个话题已经有许多很好的文章,大家参考http://www.cnblogs.com/net66/archive/2005/08/03/206132.html,其作者在文章后附加有示例项目,项目中的线程类实现了事件发送,线程终止,报告任务进度等一系列必要的功能,大家可以自己去查看代码,我就不赘述了,我主要谈微软对这个模式的实现BackgroundWorker&lt;br /&gt;&lt;br /&gt;上篇文章里说到了控制权的问题,上面的模型在winform下使用有个问题就是执行上下文的问题,在回调函数中(比如&lt;例一&gt;中的DisplayResult中),我们不得不使用BeginInvoke,才能调用ui线程创建的控件的属性和方法,&lt;br /&gt;&lt;br /&gt;比如在上面net66的例子里&lt;br /&gt;&lt;br /&gt;//创建线程对象&lt;br /&gt;  _Task = new newasynchui(); &lt;br /&gt;//挂接进度条修改事件&lt;br /&gt;  _Task.TaskProgressChanged += new TaskEventHandler( OnTaskProgressChanged1 ); &lt;br /&gt;&lt;br /&gt;//在UI线程,负责更新进度条&lt;br /&gt;private void OnTaskProgressChanged1( object sender,TaskEventArgs e ) &lt;br /&gt;{ &lt;br /&gt;if (InvokeRequired )        //不在UI线程上,异步调用&lt;br /&gt;    {&lt;br /&gt;TaskEventHandler TPChanged1 = new TaskEventHandler( OnTaskProgressChanged1 ); &lt;br /&gt;this.BeginInvoke(TPChanged1,new object[] {sender,e});&lt;br /&gt;Console.WriteLine("InvokeRequired=true");&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;progressBar.Value = e.Progress;&lt;br /&gt;}&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;可以看到,在函数里面用到了 &lt;br /&gt;&lt;br /&gt;if(InvokeRequired) &lt;br /&gt;&lt;br /&gt;{...BeginInvoke....} &lt;br /&gt;&lt;br /&gt;else &lt;br /&gt;&lt;br /&gt;{....} &lt;br /&gt;&lt;br /&gt;这个模式来保证方法在多线程和单线程下都可以运行,所以线程逻辑和界面逻辑混合在了一起,以至把以前很简单的只需要一句话的任务:progressBar.Value = e.Progress;搞的很复杂,如果线程类作为公共库来提供,对编写事件的人要求会相对较高,那么有什么更好的办法呢? &lt;br /&gt;&lt;br /&gt;其实在.Net2.0中微软自己实现这个模式,制作了Backgroundworker这个类,他可以解决上面这些问题,我们先来看看他的使用方法&lt;br /&gt;&lt;br /&gt;System.ComponentModel.BackgroundWorker bw = new System.ComponentModel.BackgroundWorker();&lt;br /&gt;&lt;br /&gt;//定义需要在子线程中干的事情&lt;br /&gt;bw.DoWork += new System.ComponentModel.DoWorkEventHandler(bw_DoWork);&lt;br /&gt;&lt;br /&gt;//定义执行完毕后需要做的事情&lt;br /&gt;bw.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);&lt;br /&gt;&lt;br /&gt;//开始执行&lt;br /&gt;bw.RunWorkerAsync();&lt;br /&gt;&lt;br /&gt;static void bw_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)&lt;br /&gt;{&lt;br /&gt;MessageBox.Show("Complete"+Thread.CurrentThread.ManagedThreadId.ToString());&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;static void bw_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)&lt;br /&gt;{&lt;br /&gt;MessageBox.Show(Thread.CurrentThread.ManagedThreadId);&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;注意我在两个函数中输出了当前线程的ID,当我们在WindowsForm程序中执行上述代码时,我们惊奇的发现,bw_RunWorkerCompleted这个回调函数居然是运行在UI线程中的,也就是说在这个方法中我们不用再使用Invoke和BeginInvoke调用winform中的控件了, 更让我奇怪的是,如果是在ConsoleApplication中同样运行这段代码,那么bw_RunWorkerCompleted输出的线程id和主线程id就并不相同. &lt;br /&gt;&lt;br /&gt;那么BackgroundWorker到底是怎么实现跨线程封送的呢? &lt;br /&gt;&lt;br /&gt;阅读一下这个类的代码,我们发现他借助了AsyncOperation.Post(SendOrPostCallback d, object arg) &lt;br /&gt;&lt;br /&gt;在winform下使用这个函数,就可以使得由SendOrPostCallback定义被封送会UI线程,聪明的博友可以用这个方法来实现自己的BackgroundWorker. &lt;br /&gt;&lt;br /&gt;继续查看下去,发现关键在于AsyncOperation的syncContext字段,这是一个SynchronizationContext类型的对象,而这个对象的Post方法具体实现了封送,当我继续查看 &lt;br /&gt;&lt;br /&gt;SynchronizationContext.Post方法时,里面简单的令人难以执行&lt;br /&gt;&lt;br /&gt;public virtual void Post(SendOrPostCallback d, object state)&lt;br /&gt;{&lt;br /&gt;ThreadPool.QueueUserWorkItem(new WaitCallback(d.Invoke), state);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;这是怎么回事情呢,线程池本省并不具备线程封送的能力啊&lt;br /&gt;&lt;br /&gt;联想到在Winform程序和Console程序下程序的行为是不同的,而且SynchronizationContext的Post方法是一个virtual方法,我猜测这个方法可能被继承自他的类重写了&lt;br /&gt;&lt;br /&gt;查询Msdn,果然发现在这个类有两个子类,其中一个就是WindowsFormsSynchronizationContext,我们来看看这个类的Post方法&lt;br /&gt;&lt;br /&gt;public override void Post(SendOrPostCallback d, object state)&lt;br /&gt;{&lt;br /&gt;if (this.controlToSendTo != null)&lt;br /&gt;{&lt;br /&gt;this.controlToSendTo.BeginInvoke(d, new object[] { state });&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;哈哈,又是熟悉的beginInvoke,原来控制台程序和Winform程序加载的SynchronizationContext是不同的,所以行为才有所不同,通过简单的测试,我们可以看到控制台程序直接使用基类(SynchronizationContext),而winform程序使用这个WindowsFormsSynchronizationContext的Post方法把方法调用封送到控件的线程.&lt;br /&gt;&lt;br /&gt;总结: 同事这个类还提供了进度改变事件,允许用户终止线程,功能全面,内部使用了线程池,能在一定成都上避免了大量线程的资源耗用问题,并通过SynchronizationContext解决了封送的问题,让我们的回调事件代码逻辑简单清晰,推荐大家使用&lt;br /&gt;&lt;br /&gt;4.&lt;br /&gt;WinForms UI Thread Invokes: An In-Depth Review of Invoke/BeginInvoke/InvokeRequred&lt;br /&gt;&lt;br /&gt;By Justin Rogers&lt;br /&gt;From http://weblogs.asp.net/justin_rogers/articles/126345.aspx&lt;br /&gt;&lt;br /&gt;Abstract:Marshalling the execution of your code onto the UI thread in the Windows Forms environment is critical to prevent cross-thread usage of UI code.  Most people don't understand how or when they'll need to use the marshalling behavior or under what circumstances it is required and when it is not.  Other users don't understand what happens when you use the marshalling behavior but it isn't needed.  In actuality it has no negative effects on stability, and instead reserves any negative side effects to performance only.&lt;br /&gt;Understanding the semantics of when your callback methods will be called, in what order, and how might be very important to your application.  In addition to the default marhalling behavior, I'll be covering special considerations for enhancing the marhsalling behavior once we fully understand how it works.  We'll also cover all of the normal scenarios and uses for code execution marhsalling to make this a complete Windows Forms marshalling document.&lt;br /&gt;TOC:&lt;br /&gt;UCS 1: Using InvokeRequired and Invoke for Synchronous Marshalling, the default scenario&lt;br /&gt;UCS 2: Using BeginInvoke for Asynchronous Marshalling&lt;br /&gt;InvokeRequired and how it works&lt;br /&gt;Invoke operation on the UI thread and from a different thread&lt;br /&gt;InvokeMarshaledCallbacks and how it handles the callback queue&lt;br /&gt;BeginInvoke operation on the UI thread and from a different thread&lt;br /&gt;UCS 3: Using BeginInvoke to change a property after other events are processed, and why it can fail&lt;br /&gt;Public and Internal Methods covered with a short description of what they do&lt;br /&gt;Conclusion&lt;br /&gt;1.  UCS 1: Using InvokeRequired and Invoke for Synchronous Marshalling, the default scenarioI call this the default scenario, because it identifies the most prominent use of UI thread marshalling.  In this scenario the user is either on the UI thread or they are not, and most likely they aren't sure.  This can occur when you use common helper methods for acting on the UI that are called from your main code (most likely on the UI thread), and in code running on worker threads.&lt;br /&gt;You can always tell if an Invoke is going to be required by calling InvokeRequired.  This method finds the thread the control's handle was created on and compares it to the current thread.  In doing so it can tell you whether or not you'll need to marshal.  This is extremely easy to use since it is a basic property on Control.  Just be aware that there is some work going on inside the method and it should have possibly been made a method instead.&lt;br /&gt;Button b = new Button(); // Creates button on the current threadif ( b.InvokeRequired ) { // This shouldn't happen since we are on the same thread }else { // We should fall into here }&lt;br /&gt;If your code is running on a thread that the control was not created on then InvokeRequired will return true.  In this case you should either call Invoke or BeginInvoke on the control before you execute any code.  Invoke can either be called with just a delegate, or you can specify arguments in the form of an object[].  This part can be confusing for a lot of users, because they don't know what they should pass to the Invoke method in order to get their code to run.  For instance, let's say you are trying to do something simple, like call a method like Focus().  Well, you could write a method that calls Focus() and then pass that to Invoke.&lt;br /&gt;myControl.Invoke(new MethodInvoker(myControl.Hide());&lt;br /&gt;Noticed I used MethodInvoker.  This is a special delegate that takes no parameters so it can be used to call any methods that take 0 parameters.  In this case Focus() takes no arguments so things work.  I'm telling the control to invoke the method right off of myControl, so I don't need any additional information.  What happens if you need to call a bunch of methods on myControl?  In that case you'll need to define a method that contains all of the code you need run and then Invoke it.&lt;br /&gt;private void BunchOfCode() {    myControl.Focus();    myControl.SomethingElse();}myControl.Invoke(new MethodInvoker(this.BunchOfCode());&lt;br /&gt;This solves one problem, but leaves another.  We just wrote code that only works only for myControl because we hard coded the control instance into our method.  We can overcome this by using an EventHandler syntax instead.  We'll cover the semantics of this later, so I'll just write some code that works now.&lt;br /&gt;private void BunchOfCode(object sender, EventArgs e) {    Control c = sender as Control;    if ( c != null ) {        c.Focus();        c.SomethingElse();    }}myControl.Invoke(new EventHandler(BunchOfCode));&lt;br /&gt;EventArgs is always going to be empty, while sender will always be the control that Invoke was called on.  There is also a generic helper method syntax you can use to circumvent any of these issues that makes use of InvokeRequired.  I'll give you a version of that works with MethodInvoker and one that works with EventHandler for completeness.&lt;br /&gt;private void DoFocusAndStuff() {    if ( myControl.InvokeRequired ) {        myControl.Invoke(new MethodInvoker(this.DoFocusAndStuff));    } else {        myControl.Focus();        myControl.SomethingElse();    }}private void DoFocusAndStuffGeneric(object sender, EventArgs e) {    Control c = sender as Control;    if ( c != null ) {        if ( c.InvokeRequired ) {            c.Invoke(new EventHandler(this.DoFocusAndStuffGeneric));        } else {            c.Focus();            c.SomethingElse();        }    }}&lt;br /&gt;Once you've set up these helper functions, you can just call them and they handle cross thread marshalling for you if needed.  Notice how each method simply calls back into itself as the target of the Invoke call.  This lets you put all of the code in a single place.  This is a great abstraction that you can add to your application to automatically handle marshalling for you.  We haven't yet had to define any new delegates to handle strange method signatures, so these techniques have low impact on the complexity of your code.  I'll wrap up the Invoke use case scenario there and move into the BeginInvoke scenario.&lt;br /&gt;2.  UCS 2: Using BeginInvoke for Asynchronous MarshallingWhenever you call Invoke, you have to wait for the return call, so your current thread hangs until the remote operation completes.  This can take some time since lots of things need to happen in order to schedule your code on the UI thread and have it execute.  While you don't really have to worry that an Invoke might block indefinitely, you still can't determine exactly how long it will take (unless it really wasn't required in the first place, but we'll get to that later).  In these cases you'll want to call Invoke asynchronously.&lt;br /&gt;Calling your code asynchronously is simliar to calling it through Invoke.  The only difference is that BeginInvoke will return immediately.  You can always check for the results of your operation by calling EndInvoke, but you don't have to.  In general, you'll almost never use EndInvoke unless you actually want the return value from the method which is fairly rare.  The same plumbing is in the back-end for BeginInvoke as for Invoke so all we'll be doing is changing our code from UCS 1 to use BeginInvoke.&lt;br /&gt;private void DoFocusAndStuff() {    if ( myControl.InvokeRequired ) {        myControl.BeginInvoke(new MethodInvoker(this.DoFocusAndStuff));    } else {        myControl.Focus();        myControl.SomethingElse();    }}private void DoFocusAndStuffGeneric(object sender, EventArgs e) {    Control c = sender as Control;    if ( c != null ) {        if ( c.InvokeRequired ) {            c.BeginInvoke(new EventHandler(this.DoFocusAndStuffGeneric));        } else {            c.Focus();            c.SomethingElse();        }    }}&lt;br /&gt;What happens if you do need the return value?  Well, then the use case changes quite a bit.  You'll need to wait until the IAsyncResult has been signalled complete and then call EndInvoke on this object to get your value.  The following code will will grab the return value and then immediately call EndInvoke.  Note that since the result is probably not ready yet, EndInvoke will hang.  Using this combination of BeginInvoke/EndInvoke is the same as just calling Invoke.&lt;br /&gt;IAsyncResult result = myControl.BeginInvoke(new MethodInvoker(myControl.Hide());myControl.EndInvoke(result);&lt;br /&gt;So we'll change our behavior to check for completion status.  We'll need to find some way to poll the completion status value so we don't hang our current thread and can continue doing work while we wait.  Normally you'll just put places in your code to check the result status and return.  We don't have the time nor space to make up such an elaborate sample here, so we'll just pretend we are doing work.&lt;br /&gt;IAsyncResult result = myControl.BeginInvoke(new MethodInvoker(myControl.Hide());while ( !result.IsCompleted ) { // Do work somehow }myControl.EndInvoke(result);&lt;br /&gt;The BeginInvoke use case scenario isn't much different from the Invoke scenario.  The underlying reason behind using one over the other is simply how long you are willing to wait for the result.  There is also the matter of whether you want the code to execute now or later.  You see, if you are on the UI thread already and issue an Invoke the code runs immediately.  If you instead issue a BeginInvoke you can continue executing your own code, and then only during the next set of activity on the message pump will the code be run.  If you have some work to finish up before you yield execution then BeginInvoke is the answer for you.&lt;br /&gt;You have to be careful when using BeginInvoke because you never know when your code will execute.  The only thing you are assured is that your code will be placed on the queue and executed in the order it was placed there.  This is the same guarantee you get for Invoke as well, though Invoke places your code on the queue and then exhausts it (running any queued operations).  We'll examine this in more detail in later sections.  For now, let's take a hard look at InvokeRequired.&lt;br /&gt;3.  InvokeRequired and how it worksThis is a read-only property that does quite a bit of work.  You could say it ran in determinate time in most cases, but there are degenerate cases where it can take much longer.  In fact the only time it is determinate is if IsHandleCreated is true meaning the control you are using is fully instantiated and has a windows handle associated with it.&lt;br /&gt;If the handle is created then control falls into the check logic to see if the windows thread process id is the same as the current thread id.  They use GetWindowThreadProcessID, a Win32 API call, to check the handle and find it's thread and process ID (note the process ID doesn't appear to be used).  Then they grab the current thread ID through none other than GetCurrentThreadID.  The result of InvokeRequired is nothing more than (threadID != currentThreadID).  Pretty basic eh?&lt;br /&gt;Things get more difficult when your control's handle is not created yet.  In this case they have to find what they call a marshalling control for your control.  This process can take some time.  They walk the entire control hiearchy trying to find out if any of your parent control's have been instantiated yet and have a valid handle.  Normally they'll find one.  As soon as they do they fall out and return that control as your marshalling control.  If they can't find any the have a fallback step.  They get the parking window.  They make one of these parking windows on every thread that has a message pump apparently, so no matter where you create your controls (no matter what thread) there should be at least one control that can be used as the marshalling control (unless maybe you are running in the designer ;-).&lt;br /&gt;Application.GetParkingWindow is nasty.  After all, this is the final fallback and the last ditch effort to find some control that can accept your windows message.  The funny thing here is that GetParkingWindow is extremely determinant if your control is already created.  They have some code that basically gets the ThreadContext given the thread ID of your control.  That is what we've been looking for this entire time, so that code-path must be used somewhere else (darn IL is getting muddied, thank god these are small methods).&lt;br /&gt;Then they start doing the magic.  They assume the control is on the current thread.  This is just an assumption, and it might not be true, but they make it for the sake of running the method.  They get the parking window off of this current TheadContext and return that.  If it hasn't been created yet, we are really screwed because that was our last chance to find a marshalling control.  At this point, if we still don't have a marshalling control, they return the original control you passed in.&lt;br /&gt;At the end of this entire process, if we find a marshalling control, that is used with GetWindowThreadProcessID.  If not, we simply return false, indicating that an Invoke is not required.  This is important.  It basically means if the handle isn't created, it doesn't matter WHAT thread you are on when you call into the control.  Reason being, is that there isn't any Handle, which means no real control exists yet, and all of the method calls will probably fail anyway (some won't, but those that require a HWND or Windows Handle will).  This also means you don't always have to call control methods on the UI thread, only those that aren't thread safe.  With InvokeRequired to the side, it is time to talk about Invoke and what it goes through.&lt;br /&gt;4.  Invoke operation on the UI thread and from a different threadTime to examine the Invoke operation and what is involed.  To start with, we'll examine what happens when the Invoke operation is happening on the same thread as the UI thread for the control.  This is a special case, since it means we don't have to marshal across a thread boundary in order to call the delegate in question.&lt;br /&gt;All of the real work happens in MarshaledInvoke.  This call is made on the marshalling control, so the first step is to get the marshaling control through FindMarshalingControl.  The first Invoke method, without arguments, calls the Invoke method with a null argument set.  The overriden Invoke in turn calls MarshaledInvoke on the marshaling control passing in the current caller (note we need this because the marshalling control might be different from the control we called Invoke on), the delegate we are marshalling, the arguments, and whether or not we want synchronous marshaling.  That second parameter is there so we can use the same method for asynchronous invokes later.&lt;br /&gt;// The method looks something like this and it is where all of the action occursobject MarshaledInvoke(Control invokeControl, Delegate delegate, object[] arguments, bool isSynchronous);&lt;br /&gt;If the handle on the marhaling control is invalid, you get the classic exception telling you the handle isn't created and that the Invoke or what not failed.  There is also some gook about ActiveX controls in there that I don't quite understand, but they appear to be demanding some permissions.  Then comes the important part for calling Invoke on the UI thread.  They again check the handle's thread id against the current thread id, and if we are running synchronously, they set a special bool indicating we are running synchronously and are operating on the same thread.  This is the short-circuit code that gets run only when you call Invoke and are on the same thread.&lt;br /&gt;Since the special case is enabled, we'll immediately call the InvokeMarshaledCallbacks method rather than posting a message to the queue.  Note all other entries into this method, and all other conditions will cause a windows message to be posted and InvokeMarshaledCallbacks will later be called from the WndProc of the control once the message is received.&lt;br /&gt;There is some more code before this point.  Basically, they make a copy of the arguments you pass in.  This is pretty smart, since I'm guessing you could try changing the arguments in the original array and thus the arguments to your delegate if they didn't make the copy.  It also means, once Invoke or BeginInvoke is called, you can change your object array of parameters, aka you can reuse the array, which is pretty nice for some scenarios.&lt;br /&gt;After they copy your parameters into a newly allocated array they take the liberty of grabbing the current stack so they can reattach it to the UI thread.  This is for security purposes so you can't try to Invoke code on the UI thread that you wouldn't have been able to run on your own thread.  They use CompressedStack for this operation and the GetCompressedStack method.  While this is a public class inside of mscorlib.dll, there is NO documentation for it.  It seems to me that this might be a very interesting security mechanism for API developers, but they don't give you any info on it.  Maybe I'll write something about how to use it later.&lt;br /&gt;With this in place, they construct a new ThreadMethodEntry.  These guys are the work horse.  They get queued into a collection, and are later used to execute your delegate.  It appears the only additional parameter used to create this class over calling MarshaledInvoke is the CompressedStack.  They also used the copied arguments array instead of the original.&lt;br /&gt;They then grab the queue for these guys off of the property bag.  You could never do this yourself, because they index the properties collection using object instances that you can't get access to.  This is a very interesting concept, to create an object used to index a hashtable or other collection that nobody else has access to.  They store all of the WinForms properties this way, as well as the events.&lt;br /&gt;Finally, they queue the ThreadMethodEntry onto the queue and continue.  They appear to do a bunch of locking to make all of this thread-safe.  While the Invoke structure is a pain in the rear, I'm glad they reserve all of this locking to a few select methods that handle all of the thread safe operations.&lt;br /&gt;Since this is an Invoke there is additional code required to make sure the operation happens synchronously.  The ThreadMethodEntry implements IAsyncResult directly, so on Invoke calls, we check to make sure it isn't already completed (a call to IsCompleted), and if it isn't, we grab the AsyncWaitHandle and do a WaitOne call.  This will block our thread until the operation completes and we can return our value.  Why did we make a call to IsCompleted first?  Well, remember that call we made to InvokeMarshaledCallbacks?  Well, when we do that our operation will already be complete once we get to that portion of the code.  If we didn't make this check and instead just started a WaitOne on the handle, we'd hang indefinitely.&lt;br /&gt;Once the operation either completes or was already completed, we look for any exceptions.  If there are exceptions, we throw them.  Here have some exceptions they say ;-)  If no exceptions were thrown then we return a special return value property stored on the ThreadMethodEntry.  This value is set in InvokeMarshaledCallbacks when we invoke the delegate.&lt;br /&gt;If you are running off the UI thread, how do things change?  Well, we don't have the special same thread operation involved this time, so instead we post a message to the marshaling control.  This is a special message that is constructed using some internal properties and then registered using RegisterWindowMessage.  This ensures that all controls will use the same message for this callback preventing us from register a bunch of custom windows messages.&lt;br /&gt;InvokeMarshaledCallbacks is an important method since it gets called both synchronously if we are on the same thread as the UI and from the WndProc in the case we aren't.  This is where all of the action of calling our delegate happens and so it is where we'll be next.&lt;br /&gt;5.  InvokeMarshaledCallbacks and how it handles the callback queueThis method is deep.  Since it has to be thread safe, we get lots of locking (even though we should only call this method from the UI thread, we have to make sure we don't step on others that are accessing the queue to add items, while we remove them).  Note that this method will continue processing the entire queue of delegates, and not just one.  Calling this method is very expensive, especially if you have a large number of delegates queued up.  You can start to better understand the performance possibilities of asynchronous programming and how you should avoid queuing up multiple delegates that are going to do the same thing (hum, maybe that IAsyncResult will come in handy after all ;-)&lt;br /&gt;We start by grabbing the delegate queue and grabbing a start entry.  Then we start up a loop to process all of the entries.  Each time through the loop the current delegate entry gets updated and as soon as we run out of elements, the loop exits.  If you were to start an asynchronous delegate from inside of another asynchronous delegate, you could probably hang your system because of the way this queue works.  So you should be careful.&lt;br /&gt;The top of the loop does work with the stack.  We grab the current stack so we can restore it later, then set the compressed stack that was saved onto the ThreadMethodEntry.  That'll ensure our security model is in place.  Then we run the delegate.  There are some defaults.  For instance, if the type is MethodInvoker, we cast it and call it using a method that yields better performance.  If the method is of type EventHandler, then we automatically set the parameters used to call the EventHandler.  In this case the sender will be the original caller, and the EventArgs will be EventArgs.Empty.  This is pretty sweet, since it simplifies calling EventHandler definitions.  It also means we can't change the sender or target of an EventHandler definition, so you have to be careful.&lt;br /&gt;If the delegate isn't of one of the two special types then we do a DynamicInvoke on it.  This is a special method on all delegates and we simply pass in our argument array.  The return value is stored on our ThreadMethodEntry and we continue.  The only special case is that of an exception.  If an exception is thrown, we store the exception on the ThreadMethodEntry and continue.&lt;br /&gt;Exiting our delegate calling code, we reset the stack frame to the saved stack frame.  We then call Complete on our ThreadMethodEntry to signal anybody waiting for it to finish.  If we are running asynchronously and there were exceptions we call Application.OnThreadException().  You may have noticed these exceptions happening in the background when you call BeginInvoke in your application, and this is where they come from.  With all of that complete, we are done.  That concludes all of the code required to understand an Invoke call, but we still have some other cases for BeginInvoke, so let's look at those.&lt;br /&gt;6.  BeginInvoke operation on the UI thread and from a different threadHow much different is BeginInvoke from the basic Invoke paradigm?  Well, not much.  There are only a couple of notes, so I don't take a bunch of your time redefining all of the logic we already discussed.  The first change is how we call MarshaledInvoke.  Instead of specifying true for running synchronously we instead specify false.  There is also no special case for running synchronously on the UI thread, instead we always post a message to the windows pump.  Finally, rather than having synchronization code on the ThreadMethodEntry, we return it immediately as an IAsyncResult that can be used to determine when the method has completed later or with EndInvoke.&lt;br /&gt;That is where all of the new logic is, EndInvoke.  You see, we need additional logic for retrieving the result of the operation and making sure it is completed.  EndInvoke can be a blocking operation if IsCompleted is not already true on the IAsyncResult.  So basically, we do a bunch of checks to make sure the IAsyncResult passed in really is a ThreadMethodEntry.  If it is, and it hasn't completed, we do the same synchronization logic we did on the Invoke version, with some small changes.  First, we try to do an InvokeMarshaledCallbacks if we are on the same thread.  This is similar to the same thread synchronization we did in the first case.  If we aren't on the same thread, then we wait on the AsyncWaitHandle.  They have some code that is dangerously close to looking like a race condition here, but I think they've properly instrumented everything to prevent that scenario.&lt;br /&gt;As we fall through all of the synchronization we again check for exceptions.  Just like with Invoke we throw them if we have them.  A lot of people don't catch these exceptions or assume they won't happen, so a lot of asynchronous code tends to fail.  Catch your exceptions people ;-)  If no exceptions were thrown then we return the value from the delegate and everything is done.&lt;br /&gt;You see, not many changes are required in order to implement BeginInvoke over top of the same code we used in Invoke.  We've already covered the changes in InvokeMarshaledCallbacks, so we appear to be complete.  Time for a sample.&lt;br /&gt;7.  UCS 3: Using BeginInvoke to change a property after other events are processed, and why it can failSometimes events in Windows Forms can transpire against you.  The classic example I use to explain this process is the AfterNodeSelect event of the TreeView control.  I generally use this event in order to update a ListBox or other control somewhere on the form, and often you want to transfer focus to a new control, probably the ListBox.  If you try to set the Focus within the event handler, then later on when the TreeView gets control back after the event, it sets the Focus right back to itself.  You feel like nothing happened, even though it did.&lt;br /&gt;You can easily fix this by using a BeginInvoke to set focus instead.  We'll call Focus directly so we need to define a new delegate.  We'll call it a BoolMethodInvoker since Focus() returns a bool, we can't just use the basic MethodInvoker delegate (what a shame eh?)&lt;br /&gt;// Declare the delegate outside of your class or as a nested class memberprivate delegate bool BoolMethodInvoker();// Issue this call from your event instead of invoking it directly.listPictures.BeginInvoke(new BoolMethodInvoker(listPictures.Focus));&lt;br /&gt;Now, knowing a bit about how the BeginInvoke stuff works, there is a way to screw yourself over.  First, your method may get executed VERY soon.  As a matter of fact, the next message on the pump might be a marshalling message, and then other messages in the pump that you wanted to go after might still be executed after you.  In many cases your method calls will still generate even more messages so this can be circumvented a bit, but possibly not.&lt;br /&gt;There is a second issue as well.  If another code source calls an Invoke and you are on the UI thread, then your method may get processed even before the event handlers are done executing and the TreeView gets control back to make it's focus call.  This is an edge case, but you can imagine you might run into scenarios where you want some asynchronous operations and some synchronous.  You need to be aware than any synchronous call can possibly affect your asynchronous calls and cause them to be processed.&lt;br /&gt;8.  Public and Internal Methods covered with a short description of what they doThese are all of the public and internal methods that we covered and what they do.  Kind of a quick reference.  I'll probably find this very helpful later when I'm trying to derive some new functionality and I don't want to have to read my entire article.&lt;br /&gt;InvokeRequired - Finds the most appropriate control and uses the handle of that control to get the thread id that created it.  If this thread id is different than the thread id of the current thread then an invoke is required, else it is not.  This method uses a number of internal methods to solve the issue of the most appropriate control.&lt;br /&gt;Invoke - This method sets up a brand new synchronous marshalled delegate.  The delegate is marshalled to the UI thread while your thread waits for the return value.&lt;br /&gt;BeginInvoke - This method sets up a brand new asynchronous marshalled delegate.  The delegate is marshalled to the UI thread while your thread continues to operate.  An extended usage of this method allows you to continue working on the UI thread and then yield execution to the message pump allowing the delegate to be called.&lt;br /&gt;EndInvoke - This method allows you to retrieve the return value of a delegate run by the BeginInvoke call.  If the delegate hasn't returned yet, EndInvoke will hang until it does.  If the delegate is alread complete, then the return value is retrieved immediately.&lt;br /&gt;MarshaledInvoke - This method queues up marshaling actions for both the Invoke and BeginInvoke layers.  Depending on the circumstances this method can either immediately execute the delegates (running on the same thread) or send a message into the message pump.  It also handles wait actions during the Invoke process or returns an IAsyncResult for use in BeginInvoke.&lt;br /&gt;InvokeMarshaledCallbacks - This method is where all of your delegates get run.  This method is either called from MarshaledInvoke or WndProc depending on the circumstances.  Once inside of this method, the entire queue of delegates is run through and all events are signalled allowing any blocking calls to operate (Invoke or EndInvoke calls) and setting all IAsyncResult objects to the IsCompleted = true state.  This method also handles exception logic allowing exceptions to be thrown back on the original thread for Invoke calls or tossed into the applications thread exception layer if you are using BeginInvoke and were running asynchronous delegates.&lt;br /&gt;FindMarshallingControl - Walks the control tree from current back up the control hierarchy until a valid control is found for purposes of finding the UI thread id.  If the control hierarchy doesn't contain a control with a valid handle, then a special parking window is retrieved.  This method is used by many of the other methods since a marshalling control is the first step in marshalling a delegate to the UI thread.&lt;br /&gt;Application.GetParkingWindow - This method takes a control and finds the marking window for it.  If the control has a valid handle then the thread id of the control is found, the ThreadContext for that thread is retreived, and the parking window is returned.  If the control does not have a valid handle then the ThreadContext of the current thread is retrieved and the parking window is returned.  If no context is found (really shouldn't happen) null is returned.&lt;br /&gt;ThreadContext.FromId - This method takes a thread id and indexes a special hash to find the context for the given thread.  If one doesn't exist then a new ThreadContext is created and returned in it's place.&lt;br /&gt;ThreadContext.FromCurrent - This method grabs the current ThreadContext out of thread local storage.  I'm guessing this must be faster than getting the current thread id and indexing the context hash, else why would they use thread local storage at all?&lt;br /&gt;ThreadContext..ctor() - This is the most confusing IL to examine, but it appears the constructor does some self registration into a context hash that the other methods use to get the context for a given thread.  They wind up using some of the Thread methods, namely SetData, to register things into thread local storage.  Why they use thread local storage and a context hash indexed by thread ID, I'm just not sure.&lt;br /&gt;9.  ConclusionYou've learned quite a bit about the Windows Forms marshalling pump today and how it handles all of the various methods of cross thread marshalling.  You've also gotten a peak deeper into the Windows Forms source through a very detailed IL inspection.  I've come up with some derived concepts based on this whole process, so maybe these will lead into some even more compelling articles.  Even more importantly, we've learned how the process can break down if we are expecting a specific order of events.&lt;br /&gt;I had never fully examined this code before, so even I was surprised at some of what I found.  For instance, the performance implications of calling the same method multiple times asynchronously might be something that should be considered.  Knowing that all delegates will be processed in a tight loop is pretty huge and that items can be queued while others are being dequeued (aka you can hang yourself).  Finally, the realization that if you use an EventHandler type, you can't pass in the sender explicitly might lead to confusion for some folks.  After all, if you mock up an arguments array and pass it to Invoke or BeginInvoke you would expect it to be used.&lt;br /&gt;&lt;br /&gt;5.&lt;br /&gt;在多线程中如何调用Winform &lt;br /&gt;&lt;br /&gt;From http://blog.csdn.net/sangzier/archive/2004/11/01/162310.aspx&lt;br /&gt;&lt;br /&gt;问题的产生：&lt;br /&gt;&lt;br /&gt;　　我的WinForm程序中有一个用于更新主窗口的工作线程（worker thread），但文档中却提示我不能在多线程中调用这个form（为什么？），而事实上我在调用时程序常常会崩掉。请问如何从多线程中调用form中的方法呢？ &lt;br /&gt;&lt;br /&gt;　　解答：&lt;br /&gt;&lt;br /&gt;　　每一个从Control类中派生出来的WinForm类（包括Control类）都是依靠底层Windows消息和一个消息泵循环（message pump loop）来执行的。消息循环都必须有一个相对应的线程，因为发送到一个window的消息实际上只会被发送到创建该window的线程中去。其结果是，即使提供了同步（synchronization），你也无法从多线程中调用这些处理消息的方法。大多数plumbing是掩藏起来的，因为WinForm是用代理（delegate）将消息绑定到事件处理方法中的。WinForm将Windows消息转换为一个基于代理的事件，但你还是必须注意，由于最初消息循环的缘故，只有创建该form的线程才能调用其事件处理方法。如果你在你自己的线程中调用这些方法，则它们会在该线程中处理事件，而不是在指定的线程中进行处理。你可以从任何线程中调用任何不属于消息处理的方法。&lt;br /&gt;&lt;br /&gt;　　Control类（及其派生类）实现了一个定义在System.ComponentModel命名空间下的接口 -- ISynchronizeInvoke，并以此来处理多线程中调用消息处理方法的问题：&lt;br /&gt;&lt;br /&gt;public interface ISynchronizeInvoke&lt;br /&gt;{&lt;br /&gt;　object Invoke(Delegate　method,object[] args);&lt;br /&gt;　IAsyncResult BeginInvoke(Delegate　method,object[] args);&lt;br /&gt;　object EndInvoke(IAsyncResult result);&lt;br /&gt;　bool InvokeRequired {get;}&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;　　ISynchronizeInvoke提供了一个普通的标准机制用于在其他线程的对象中进行方法调用。例如，如果一个对象实现了ISynchronizeInvoke，那么在线程T1上的客户端可以在该对象中调用ISynchronizeInvoke的Invoke()方法。Invoke()方法的实现会阻塞（block）该线程的调用，它将调用打包发送（marshal）到 T2，并在T2中执行调用，再将返回值发送会T1，然后返回到T1的客户端。Invoke()方法以一个代理来定位该方法在T2中的调用，并以一个普通的对象数组做为其参数。&lt;br /&gt;&lt;br /&gt;　　调用者还可以检查InvokeRequired属性，因为你既可以在同一线程中调用ISynchronizeInvoke也可以将它重新定位（redirect）到其他线程中去。如果InvokeRequired的返回值是false的话，则调用者可以直接调用该对象的方法。&lt;br /&gt;&lt;br /&gt;　　比如，假设你想要从另一个线程中调用某个form中的Close方法，那么你可以使用预先定义好的的MethodInvoker代理，并调用Invoke方法:&lt;br /&gt;&lt;br /&gt;Form form;&lt;br /&gt;/* obtain a reference to the form, &lt;br /&gt;then: */&lt;br /&gt;ISynchronizeInvoke synchronizer;&lt;br /&gt;synchronizer = form;&lt;br /&gt;&lt;br /&gt;if(synchronizer.InvokeRequired)&lt;br /&gt;{&lt;br /&gt;MethodInvoker invoker = new &lt;br /&gt;MethodInvoker(form.Close);&lt;br /&gt;synchronizer.Invoke(invoker,null);&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;form.Close(); &lt;br /&gt;&lt;br /&gt;　　ISynchronizeInvoke不仅仅用于WinForm中。例如，一个Calculator类提供了将两个数字相加的Add()方法，它就是通过ISynchronizeInvoke来实现的。用户必须确定ISynchronizeInvoke.Invoke()方法的调用是执行在正确的线程中的。&lt;br /&gt;&lt;br /&gt;　　C# 在正确的线程中写入调用&lt;br /&gt;&lt;br /&gt;　　列表A. Calculator类的Add()方法用于将两个数字相加。如果用户直接调用Add()方法，它会在该用户的线程中执行调用，而用户可以通过ISynchronizeInvoke.Invoke()将调用写入正确的线程中。 &lt;br /&gt;　　列表A:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public class Calculator : ISynchronizeInvoke&lt;br /&gt;{&lt;br /&gt;　public int Add(int arg1,int arg2)&lt;br /&gt;　{　&lt;br /&gt;　　int threadID = Thread.CurrentThread.GetHashCode();&lt;br /&gt;　　Trace.WriteLine( "Calculator thread ID is " + threadID.ToString());&lt;br /&gt;　　return arg1 + arg2;&lt;br /&gt;　}&lt;br /&gt;　//ISynchronizeInvoke implementation &lt;br /&gt;　public object Invoke(Delegate method,object[] args)&lt;br /&gt;　{&lt;br /&gt;　　public IAsyncResult BeginInvoke(Delegate method,object[] args)&lt;br /&gt;　　{&lt;br /&gt;　　　public object EndInvoke(IAsyncResult result)&lt;br /&gt;　　　{&lt;br /&gt;　　　　public bool InvokeRequired&lt;br /&gt;　　　　{&lt;br /&gt;　　　　}&lt;br /&gt;　　　}&lt;br /&gt;　　　//Client-side code&lt;br /&gt;　　　public delegate int AddDelegate(int arg1,int arg2);&lt;br /&gt;&lt;br /&gt;　　　　int threadID = Thread.CurrentThread.GetHashCode();&lt;br /&gt;　　　　Trace.WriteLine("Client thread ID is " + threadID.ToString());&lt;br /&gt;&lt;br /&gt;　　　　Calculator calc;&lt;br /&gt;　　　　/* Some code to initialize calc */&lt;br /&gt;&lt;br /&gt;　　　　AddDelegate addDelegate = new AddDelegate(calc.Add);&lt;br /&gt;&lt;br /&gt;　　　　object[] arr = new object[2];&lt;br /&gt;　　　　arr[0] = 3;&lt;br /&gt;　　　　arr[1] = 4;&lt;br /&gt;&lt;br /&gt;　　　　int sum = 0;&lt;br /&gt;　　　　sum = (int) calc.Invoke(addDelegate,arr);&lt;br /&gt;　　　　Debug.Assert(sum ==7);&lt;br /&gt;&lt;br /&gt;　　　　/* Possible output:&lt;br /&gt;　　　　Calculator thread ID is 29&lt;br /&gt;　　　　Client thread ID is 30 &lt;br /&gt;　　　　*/&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;　　或许你并不想进行同步调用，因为它被打包发送到另一个线程中去了。你可以通过BeginInvoke()和EndInvoke()方法来实现它。你可以依照通用的.NET非同步编程模式（asynchronous programming model）来使用这些方法：用BeginInvoke()来发送调用，用EndInvoke()来实现等待或用于在完成时进行提示以及收集返回结果。&lt;br /&gt;&lt;br /&gt;　　还值得一提的是ISynchronizeInvoke方法并非安全类型。 类型不符会导致在执行时被抛出异常，而不是编译错误。所以在使用ISynchronizeInvoke时要格外注意，因为编辑器无法检查出执行错误。&lt;br /&gt;&lt;br /&gt;　　实现ISynchronizeInvoke要求你使用一个代理来在后期绑定（late binding）中动态地调用方法。每一种代理类型均提供DynamicInvoke()方法： public object DynamicInvoke(object[] &lt;br /&gt;args);&lt;br /&gt;&lt;br /&gt;　　理论上来说，你必须将一个方法代理放到一个需要提供对象运行的真实的线程中去，并使Invoke() 和BeginInvoke()方法中的代理中调用DynamicInvoke()方法。ISynchronizeInvoke的实现是一个非同一般的编程技巧，本文附带的源文件中包含了一个名为Synchronizer的帮助类（helper class）和一个测试程序，这个测试程序是用来论证列表A中的Calculator类是如何用Synchronizer类来实现ISynchronizeInvoke的。Synchronizer是ISynchronizeInvoke的一个普通实现，你可以使用它的派生类或者将其本身作为一个对象来使用，并将ISynchronizeInvoke实现指派给它。 &lt;br /&gt;&lt;br /&gt;　　用来实现Synchronizer的一个重要元素是使用一个名为WorkerThread的嵌套类（nested class）。WorkerThread中有一个工作项目（work item）查询。WorkItem类中包含方法代理和参数。Invoke()和BeginInvoke()用来将一个工作项目实例加入到查询里。WorkerThread新建一个.NET worker线程，它负责监测工作项目的查询任务。查询到项目之后，worker会读取它们，然后调用DynamicInvoke()方法。&lt;br /&gt;&lt;br /&gt;6.&lt;br /&gt;通过多线程为基于 .NET 的应用程序实现响应迅速的用户&lt;br /&gt;&lt;br /&gt;http://www.microsoft.com/china/MSDN/library/enterprisedevelopment/&lt;br /&gt;softwaredev/misMultithreading.mspx&lt;br /&gt;&lt;br /&gt;From http://www.vckbase.com/document/viewdoc/?id=1126&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-110263943949619760?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/110263943949619760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/110263943949619760'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2004/08/processthread-and-thread-in-c.html' title='ProcessThread and Thread in C#'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-8105129262071529265</id><published>2006-12-22T23:47:00.000-08:00</published><updated>2008-01-15T00:05:39.752-08:00</updated><title type='text'>Some notes on ThreadPool - 2</title><content type='html'>1.&lt;br /&gt;From http://www.blogcn.com/User8/flier_lu/blog/58180631.html&lt;br /&gt;&lt;br /&gt;也谈大规模定时器的实时集中管理实现 [草稿] [原] &lt;br /&gt;&lt;br /&gt;    温少在其最近的一篇blog里面，介绍了对 java.util.concurrent 中延迟队列 DelayQueue 的使用体会： 《精巧好用的DelayQueue》。溢美之辞我就不多说了，这个不是我擅长的；大家这么熟又特地问到我头上，那就不客气的提出一些自己的看法，希望能借此机会互相讨论，把类似问题的认识深化一下。&lt;br /&gt;    既然讨论 DelayQueue 那么不妨把目标范围权且定在，对大量定时器类似对象的实时集中管理上。这个大量的概念，是指同时有至少存在万这个数量级的定时器。对一个大型网络应用程序，或者复杂事务应用系统，经常存在这此类需求，例如并行跟踪几十万用户会话的超时情况，或者十几万个缓存对象的超时等等；另一个前提是实时集中管理，假定这些定时器通常情况下是活跃的，需要隔段时间被激活或重调度，毕竟大部分定时器的使用并非一次性的。而在上述定义讨论范围之外的需求，可以考虑直接用 Java 内置的 Timer/ScheduleExecutor 或者更加强大的 Quartz 调度库。&lt;br /&gt;&lt;br /&gt;http://www.opensymphony.com/quartz/&lt;br /&gt;&lt;br /&gt;    在这样一个前提下，我们可以来看看对定时器队列的日常操作，有哪些是可以进行优化的。&lt;br /&gt;&lt;br /&gt;    首先，新增一个定时器，隐式包含了创建内部结构，和放入到下次可被调度位置的操作。对 DelayQueue 实现来说，其内部使用一个 PriorityQueue 在插入定时器时按触发时间进行排序。这看起来是一个很精巧的实现，但个人觉得纯属提前优化，毕竟这个定时器会不会被调度到都是问题，而且插入和排序时需要锁住整个队列，效率和并行性堪忧。&lt;br /&gt;    其次，处理下一个定时器时，DelayQueue 的实现隐式包含了等待的语义。我不太了解其设计时的需求，以及对精度的要求；但就一个高性能网络程序的需求来说，在每秒处理几千甚至上万报文的情况下，任何等待语义都是昂贵且不可接受的。而且除非是实时或者非抢占调度的操作系统，否则毫秒一级的等待都是没什么实际意义的，远不如使用基于高精度计数器的差值检查来得实在。&lt;br /&gt;    此外，基于队列的设计基本上是无法兼顾取消定时器语义的，任何对现有队列中定时器的操作，如重新激活或取消，都需要锁定并遍历完整的定时器队列，而这类需求在日常工作中是非常常见的。&lt;br /&gt;&lt;br /&gt;    尽管有上述这些缺点，但对于绝大多数的应用来说，DelayQueue 的确算的上是一个精巧实用的实现，可以在相当程度上改进我们的超时机制。&lt;br /&gt;&lt;br /&gt;    说了一堆意见，下面介绍一个个人比较喜欢的实现思路：Timer Wheel 算法&lt;br /&gt;&lt;br /&gt;    Redesigning the BSD Callout and Timer Facilities (1995)&lt;br /&gt;&lt;br /&gt;http://citeseer.ist.psu.edu/83774.html&lt;br /&gt;&lt;br /&gt;    这个算法最早是被设计用来实现 BSD 内核中定时器的，后来被广泛移植到诸如 ACE 等框架中，堪称 BSD 中经典算法之一，能针对定时器的各类常见操作提供接近常数时间的响应，且能根据需要很容易进行扩展，下面我们来简要介绍一下：&lt;br /&gt;&lt;br /&gt;    首先，整个算法是基于一个大的 Hash 表，可以把它想象成一个左轮手枪的枪膛，不同的定时器根据预期触发时间的不同，在插入时被放入不同的子弹槽内。这个插入过程完全不需要考虑排序，只是一个最简单的 hash 操作，加上一个 Wait-Free 的链表插入。&lt;br /&gt;    其次，每次一个时间单位过去后，枪机指向转轮的下一个位置，里面所有的定时器被检查超时状态。代码上可以就是简单的超时值减减和比较，如果过期则触发此定时器并抛弃之。&lt;br /&gt;    最后，在取消或者更新定时器时，最坏情况需要对一个子弹槽中所有的定时器进行遍历。&lt;br /&gt;&lt;br /&gt;    因为手头没有开发环境，只能把算法思路用伪代码大概写写，有没写明白的以那篇论文为准，哈哈，回头有空再补完整实现 :P&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;以下为引用：&lt;br /&gt;&lt;br /&gt;void insert(Callable callable, long expired)&lt;br /&gt;{&lt;br /&gt;  Node node = new Node();&lt;br /&gt;  node._callable = callable&lt;br /&gt;  node._expired = expired - System.currentTimeMillis();&lt;br /&gt;  node._next = _wheel[expired % _wheel_size]._head;&lt;br /&gt;  node._next._prev = node&lt;br /&gt;  _wheel[node._expired % _hash_size]._head = node;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void check(long time)&lt;br /&gt;{&lt;br /&gt;  for (Node node = _wheel[time % _wheel_size]._head;&lt;br /&gt;       node != null; node = node._next)&lt;br /&gt;  {&lt;br /&gt;    if (--node._expired &lt; 0)&lt;br /&gt;    {&lt;br /&gt;      node._callable.call();&lt;br /&gt;      node._prev._next = node._next;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void cancel(Callable callable)&lt;br /&gt;{&lt;br /&gt;  for (int i=0; i&lt;_hash_size; i++)&lt;br /&gt;  {&lt;br /&gt;    for (Node node = _wheel[expired % _wheel_size]._head;&lt;br /&gt;       node != null; node = node._next)&lt;br /&gt;    {&lt;br /&gt;      if (node._callable == callable)&lt;br /&gt;      {&lt;br /&gt;        node._prev._next = node._next;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void update(Callable callable, long expired)&lt;br /&gt;{&lt;br /&gt;  cancel(callable);&lt;br /&gt;  insert(callable, expired);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;2.&lt;br /&gt;from http://www.cnblogs.com/yizhu2000/archive/2008/01/03/1011958.html&lt;br /&gt;&lt;br /&gt;基础篇&lt;br /&gt; &lt;br /&gt;怎样创建一个线程 &lt;br /&gt;&lt;br /&gt;我只简单列举几种常用的方法&lt;br /&gt;&lt;br /&gt;一）使用Thread类 &lt;br /&gt;&lt;br /&gt;ThreadStart threadStart=new ThreadStart(Calculate);//通过ThreadStart委托告诉子线程讲执行什么方法,这里执行一个计算圆周长的方法&lt;br /&gt;Thread thread=new Thread(threadStart);&lt;br /&gt;thread.Start(); //启动新线程&lt;br /&gt;&lt;br /&gt;public void Calculate(){&lt;br /&gt;double Diameter=0.5;&lt;br /&gt;Console.Write("The perimeter Of Circle with a Diameter of {0} is {1}"Diameter,Diameter*Math.PI);&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;二）使用Delegate.BeginInvoke &lt;br /&gt;&lt;br /&gt;delegate double CalculateMethod(double Diameter); //申明一个委托，表明需要在子线程上执行的方法的函数签名&lt;br /&gt;static CalculateMethod calcMethod = new CalculateMethod(Calculate);//把委托和具体的方法关联起来&lt;br /&gt;static void Main(string[] args)&lt;br /&gt;{&lt;br /&gt;//此处开始异步执行,并且可以给出一个回调函数(如果不需要执行什么后续操作也可以不使用回调)&lt;br /&gt;calcMethod.BeginInvoke(5, new AsyncCallback(TaskFinished), null);&lt;br /&gt;Console.ReadLine();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//线程调用的函数,给出直径作为参数,计算周长&lt;br /&gt;public static double Calculate(double Diameter)&lt;br /&gt;{&lt;br /&gt;    return Diameter * Math.PI;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;//线程完成之后回调的函数&lt;br /&gt;public static void TaskFinished(IAsyncResult result)&lt;br /&gt;{&lt;br /&gt;    double re = 0;&lt;br /&gt;    re = calcMethod.EndInvoke(result);&lt;br /&gt;    Console.WriteLine(re);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;三）使用ThreadPool.QueueworkItem &lt;br /&gt;&lt;br /&gt;WaitCallback w = new WaitCallback(Calculate);&lt;br /&gt;//下面启动四个线程,计算四个直径下的圆周长&lt;br /&gt;ThreadPool.QueueUserWorkItem(w, 1.0);&lt;br /&gt;ThreadPool.QueueUserWorkItem(w, 2.0);&lt;br /&gt;ThreadPool.QueueUserWorkItem(w, 3.0);&lt;br /&gt;ThreadPool.QueueUserWorkItem(w, 4.0);&lt;br /&gt;public static void Calculate(double Diameter)&lt;br /&gt;{&lt;br /&gt;return Diameter * Math.PI;&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;下面两条来自于http://www.cnblogs.com/tonyman/archive/2007/09/13/891912.html&lt;br /&gt;&lt;br /&gt;受托管的线程与 Windows线程&lt;br /&gt;&lt;br /&gt;必须要了解，执行.NET应用的线程实际上仍然是Windows线程。但是，当某个线程被CLR所知时，我们将它称为受托管的线程。具体来说，由受托管的代码创建出来的线程就是受托管的线程。如果一个线程由非托管的代码所创建，那么它就是非托管的线程。不过，一旦该线程执行了受托管的代码它就变成了受托管的线程。 &lt;br /&gt;&lt;br /&gt;一个受托管的线程和非托管的线程的区别在于，CLR将创建一个System.Threading.Thread类的实例来代表并操作前者。在内部实现中，CLR将一个包含了所有受托管线程的列表保存在一个叫做ThreadStore地方。 &lt;br /&gt;&lt;br /&gt;CLR确保每一个受托管的线程在任意时刻都在一个AppDomain中执行，但是这并不代表一个线程将永远处在一个AppDomain中，它可以随着时间的推移转到其他的AppDomain中。 &lt;br /&gt;&lt;br /&gt;从安全的角度来看，一个受托管的线程的主用户与底层的非托管线程中的Windows主用户是无关的。&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;前台线程与后台线程&lt;br /&gt;&lt;br /&gt;启动了多个线程的程序在关闭的时候却出现了问题，如果程序退出的时候不关闭线程，那么线程就会一直的存在，但是大多启动的线程都是局部变量，不能一一的关闭，如果调用Thread.CurrentThread.Abort()方法关闭主线程的话，就会出现ThreadAbortException 异常，因此这样不行。&lt;br /&gt;后来找到了这个办法： Thread.IsBackground 设置线程为后台线程。&lt;br /&gt; &lt;br /&gt;msdn对前台线程和后台线程的解释：托管线程或者是后台线程，或者是前台线程。后台线程不会使托管执行环境处于活动状态，除此之外，后台线程与前台线程是一样的。一旦所有前台线程在托管进程（其中 .exe 文件是托管程序集）中被停止，系统将停止所有后台线程并关闭。通过设置 Thread.IsBackground 属性，可以将一个线程指定为后台线程或前台线程。例如，通过将 Thread.IsBackground 设置为 true，就可以将线程指定为后台线程。同样，通过将 IsBackground 设置为 false，就可以将线程指定为前台线程。从非托管代码进入托管执行环境的所有线程都被标记为后台线程。通过创建并启动新的 Thread 对象而生成的所有线程都是前台线程。如果要创建希望用来侦听某些活动（如套接字连接）的前台线程，则应将 Thread.IsBackground 设置为 true，以便进程可以终止。 &lt;br /&gt;所以解决办法就是在主线程初始化的时候，设置：Thread.CurrentThread.IsBackground = true; &lt;br /&gt;&lt;br /&gt;这样，主线程就是后台线程，在关闭主程序的时候就会关闭主线程，从而关闭所有线程。但是这样的话，就会强制关闭所有正在执行的线程，所以在关闭的时候要对线程工作的结果保存。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;经常看到名为BeginXXX和EndXXX的方法，他们是做什么用的 &lt;br /&gt;&lt;br /&gt;这是.net的一个异步方法名称规范&lt;br /&gt;.Net在设计的时候为异步编程设计了一个异步编程模型（APM），这个模型不仅是使用.NET的开发人员使用，.Net内部也频繁用到，比如所有的Stream就有BeginRead，EndRead，Socket,WebRequet,SqlCommand都运用到了这个模式，一般来讲，调用BegionXXX的时候，一般会启动一个异步过程去执行一个操作，EndEnvoke可以接收这个异步操作的返回，当然如果异步操作在EndEnvoke调用的时候还没有执行完成，EndInvoke会一直等待异步操作完成或者超时 &lt;br /&gt;&lt;br /&gt;.Net的异步编程模型（APM）一般包含BeginXXX，EndXXX，IAsyncResult这三个元素，BeginXXX方法都要返回一个IAsyncResult，而EndXXX都需要接收一个IAsyncResult作为参数，他们的函数签名模式如下 &lt;br /&gt;&lt;br /&gt;IAsyncResult BeginXXX(...);&lt;br /&gt;&lt;br /&gt;&lt;返回类型&gt; EndXXX(IAsyncResult ar)； &lt;br /&gt;&lt;br /&gt;BeginXXX和EndXXX中的XXX，一般都对应一个同步的方法,比如FileStream的Read方法是一个同步方法，相应的BeginRead(),EndRead()就是他的异步版本，HttpRequest有GetResponse来同步接收一个响应，也提供了BeginGetResponse和EndGetResponse这个异步版本，而IAsynResult是二者联系的纽带，只有把BeginXXX所返回的IAsyncResult传给对应的EndXXX，EndXXX才知道需要去接收哪个BeginXXX发起的异步操作的返回值。&lt;br /&gt;&lt;br /&gt;这个模式在实际使用时稍显繁琐,虽然原则上我们可以随时调用EndInvoke来获得返回值,并且可以同步多个线程,但是大多数情况下当我们不需要同步很多线程的时候使用回调是更好的选择,在这种情况下三个元素中的IAsynResult就显得多余,我们一不需要用其中的线程完结标志来判断线程是否成功完成(回调的时候线程应该已经完成了),二不需要他来传递数据,因为数据可以写在任何变量里,并且回调时应该已经填充,所以可以看到微软在新的.Net Framework中已经加强了对回调事件的支持,这总模型下,典型的回调程序应该这样写&lt;br /&gt;&lt;br /&gt;a.DoWork+=new SomeEventHandler(Caculate);&lt;br /&gt;a.CallBack+=new SomeEventHandler(callback);&lt;br /&gt;a.Run();&lt;br /&gt;&lt;br /&gt;（注：我上面讲的是普遍的用法，然而BeginXXX，EndXXX仅仅是一种模式，而对这个模式的实现完全取决于使用他的开发人员，具体实现的时候你可以使用另外一个线程来实现异步，也可能使用硬件的支持来实现异步，甚至可能根本和异步没有关系（尽管几乎没有人会这样做）-----比如直接在Beginxxx里直接输出一个"Helloworld"，如果是这种极端的情况，那么上面说的一切都是废话，所以上面的探讨并不涉及内部实现，只是告诉大家微软的模式，和框架中对这个模式的经典实现） &lt;br /&gt;&lt;br /&gt;异步和多线程有什么关联 &lt;br /&gt;&lt;br /&gt;有一句话总结的很好：多线程是实现异步的一种手段和工具 &lt;br /&gt;&lt;br /&gt;我们通常把多线程和异步等同起来，实际是一种误解，在实际实现的时候，异步有许多种实现方法，我们可以用进程来做异步，或者使用纤程，或者硬件的一些特性，比如在实现异步IO的时候,可以有下面两个方案:&lt;br /&gt;&lt;br /&gt;1)可以通过初始化一个子线程，然后在子线程里进行IO，而让主线程顺利往下执行，当子线程执行完毕就回调&lt;br /&gt;&lt;br /&gt;2)也可以根本不使用新线程，而使用硬件的支持（现在许多硬件都有自己的处理器），来实现完全的异步，这是我们只需要将IO请求告知硬件驱动程序，然后迅速返回，然后等着硬件IO就绪通知我们就可以了&lt;br /&gt;&lt;br /&gt;实际上DotNet Framework里面就有这样的例子，当我们使用文件流的时候，如果制定文件流属性为同步，则使用BeginRead进行读取时，就是用一个子线程来调用同步的Read方法，而如果指定其为异步，则同样操作时就使用了需要硬件和操作系统支持的所谓IOCP的机制&lt;br /&gt;&lt;br /&gt;WinForm多线程编程篇 &lt;br /&gt;&lt;br /&gt;我的多线程WinForm程序老是抛出InvalidOperationException ，怎么解决？ &lt;br /&gt;&lt;br /&gt;在WinForm中使用多线程时，常常遇到一个问题，当在子线程（非UI线程）中修改一个控件的值：比如修改进度条进度，时会抛出如下错误 &lt;br /&gt;&lt;br /&gt;Cross-thread operation not valid: Control 'XXX' accessed from a thread other than the thread it was created on. &lt;br /&gt;&lt;br /&gt;在VS2005或者更高版本中，只要不是在控件的创建线程（一般就是指UI主线程）上访问控件的属性就会抛出这个错误，解决方法就是利用控件提供的Invoke和BeginInvoke把调用封送回UI线程，也就是让控件属性修改在UI线程上执行，下面列出会报错的代码和他的修改版本 &lt;br /&gt;&lt;br /&gt;ThreadStart threadStart=new ThreadStart(Calculate);//通过ThreadStart委托告诉子线程讲执行什么方法&lt;br /&gt;Thread thread=new Thread(threadStart);&lt;br /&gt;thread.Start();&lt;br /&gt;public void Calculate(){&lt;br /&gt;    double Diameter=0.5;&lt;br /&gt;    double result=Diameter*Math.PI;&lt;br /&gt;    CalcFinished(result);//计算完成需要在一个文本框里显示&lt;br /&gt;}&lt;br /&gt;public void CalcFinished(double result){&lt;br /&gt;    this.TextBox1.Text=result.ToString();//会抛出错误&lt;br /&gt;}&lt;br /&gt;上面加粗的地方在debug的时候会报错，最直接的修改方法是修改Calculate这个方法如下 &lt;br /&gt;&lt;br /&gt;delegate void changeText(double result);&lt;br /&gt;&lt;br /&gt;public void Calculate(){&lt;br /&gt;    double Diameter=0.5;&lt;br /&gt;    double result=Diameter*Math.PI;&lt;br /&gt;    this.BeginInvoke(new changeText(CalcFinished),t.Result);//计算完成需要在一个文本框里显示&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;这样就ok了，但是最漂亮的方法是不去修改Calculate，而去修改CalcFinished这个方法，因为程序里调用这个方法的地方可能很多，由于加了是否需要封送的判断,这样修改还能提高非跨线程调用时的性能&lt;br /&gt;&lt;br /&gt;delegate void changeText(double result);&lt;br /&gt;&lt;br /&gt;public void CalcFinished(double result){&lt;br /&gt;    if(this.InvokeRequired){&lt;br /&gt;        this.BeginInvoke(new changeText(CalcFinished),t.Result);&lt;br /&gt;    }&lt;br /&gt;    else{&lt;br /&gt;        this.TextBox1.Text=result.ToString();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;上面的做法用到了Control的一个属性InvokeRequired（这个属性是可以在其他线程里访问的）,这个属性表明调用是否来自另非UI线程,如果是,则使用BeginInvoke来调用这个函数,否则就直接调用,省去线程封送的过程&lt;br /&gt;&lt;br /&gt;Invoke，BeginInvoke干什么用的，内部是怎么实现的?&lt;br /&gt;这两个方法主要是让给出的方法在控件创建的线程上执行&lt;br /&gt;&lt;br /&gt;Invoke使用了Win32API的SendMessage,&lt;br /&gt;&lt;br /&gt;UnsafeNativeMethods.PostMessage(new HandleRef(this, this.Handle), threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);&lt;br /&gt;&lt;br /&gt;BeginInvoke使用了Win32API的PostMessage&lt;br /&gt;&lt;br /&gt;UnsafeNativeMethods.PostMessage(new HandleRef(this, this.Handle), threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);&lt;br /&gt;&lt;br /&gt;这两个方法向UI线程的消息队列中放入一个消息,当UI线程处理这个消息时,就会在自己的上下文中执行传入的方法,换句话说凡是使用BeginInvoke和Invoke调用的线程都是在UI主线程中执行的,所以如果这些方法里涉及一些静态变量,不用考虑加锁的问题&lt;br /&gt;&lt;br /&gt;每个线程都有消息队列吗?&lt;br /&gt;不是,只有创建了窗体对象的线程才会有消息队列(下面给出&lt;Windows 核心编程&gt;关于这一段的描述)&lt;br /&gt;&lt;br /&gt;当一个线程第一次被建立时，系统假定线程不会被用于任何与用户相关的任务。这样可以减少线程对系统资源的要求。但是，一旦这个线程调用一个与图形用户界面有关的函数（例如检查它的消息队列或建立一个窗口），系统就会为该线程分配一些另外的资源，以便它能够执行与用户界面有关的任务。特别是，系统分配一个T H R E A D I N F O结构，并将这个数据结构与线程联系起来。 &lt;br /&gt;&lt;br /&gt;这个T H R E A D I N F O结构包含一组成员变量，利用这组成员，线程可以认为它是在自己独占的环境中运行。T H R E A D I N F O是一个内部的、未公开的数据结构，用来指定线程的登记消息队列（posted-message queue）、发送消息队列（ send-message queue）、应答消息队列（ r e p l y -message queue）、虚拟输入队列（virtualized-input queue）、唤醒标志（wake flag）、以及用来描述线程局部输入状态的若干变量。图2 6 - 1描述了T H R E A D I N F O结构和与之相联系的三个线程。 &lt;br /&gt;&lt;br /&gt;为什么Winform不允许跨线程修改UI线程控件的值&lt;br /&gt;&lt;br /&gt;在vs2003下,使用子线程调用ui线程创建的控件的属性是不会有问题的,但是编译的时候会出现警告,但是vs2005及以上版本就会有这样的问题,下面是msdn上的描述 &lt;br /&gt;&lt;br /&gt;"当您在 Visual Studio 调试器中运行代码时，如果您从一个线程访问某个 UI 元素，而该线程不是创建该 UI 元素时所在的线程，则会引发 InvalidOperationException。调试器引发该异常以警告您存在危险的编程操作。UI 元素不是线程安全的，所以只应在创建它们的线程上进行访问" &lt;br /&gt;&lt;br /&gt;从上面可以看出,这个异常实际是debugger耍的花招,也就是说,如果你直接运行程序的exe文件,或者利用运行而不调试(Ctrl+F5)来运行你的程序,是不会抛出这样的异常的.大概ms发现v2003的警告对广大开发者不起作用,所以用了一个比较狠一点的方法. &lt;br /&gt;&lt;br /&gt;不过问题依然存在:既然这样设计的原因主要是因为控件的值非线程安全,那么DotNet framework中非线程安全的类千千万万,为什么偏偏跨线程修改Control的属性会有这样严格的限制策略呢? &lt;br /&gt;&lt;br /&gt;这个问题我还回答不好,希望博友们能够予以补充 &lt;br /&gt;&lt;br /&gt;有没有什么办法可以简化WinForm多线程的开发&lt;br /&gt;&lt;br /&gt;使用backgroundworker,使用这个组建可以避免回调时的Invoke和BeginInvoke,并且提供了许多丰富的方法和事件&lt;br /&gt;&lt;br /&gt;线程池 &lt;br /&gt;&lt;br /&gt;线程池的作用是什么 &lt;br /&gt;&lt;br /&gt;作用是减小线程创建和销毁的开销 &lt;br /&gt;&lt;br /&gt;创建线程涉及用户模式和内核模式的切换，内存分配，dll通知等一系列过程，线程销毁的步骤也是开销很大的，所以如果应用程序使用了完一个线程，我们能把线程暂时存放起来，以备下次使用，就可以减小这些开销 &lt;br /&gt;&lt;br /&gt;所有进程使用一个共享的线程池,还是每个进程使用独立的线程池? &lt;br /&gt;&lt;br /&gt;每个进程都有一个线程池,一个Process中只能有一个实例，它在各个应用程序域（AppDomain）是共享的，.Net2.0 中默认线程池的大小为工作线程25个,IO线程1000个,有一个比较普遍的误解是线程池中会有1000个线程等着你去取,其实不然, ThreadPool仅仅保留相当少的线程，保留的线程可以用SetMinThread这个方法来设置，当程序的某个地方需要创建一个线程来完成工作时，而线程池中又没有空闲线程时,线程池就会负责创建这个线程,并且在调用完毕后,不会立刻销毁,而是把他放在池子里,预备下次使用,同时如果线程超过一定时间没有被使用,线程池将会回收线程，所以线程池里存在的线程数实际是个动态的过程 &lt;br /&gt;&lt;br /&gt;为什么不要手动线程池设置最大值? &lt;br /&gt;&lt;br /&gt;当我首次看到线程池的时候,脑袋里的第一个念头就是给他设定一个最大值,然而当我们查看ThreadPool的SetMaxThreads文档时往往会看到一条警告:不要手动更改线程池的大小,这是为什么呢? &lt;br /&gt;&lt;br /&gt;其实无论FileStream的异步读写,异步发送接受Web请求,甚至使用delegate的beginInvoke都会默认调用 ThreadPool,也就是说不仅你的代码可能使用到线程池,框架内部也可能使用到,更改的后果影响就非常大,特别在iis中,一个应用程序池中的所有 WebApplication会共享一个线程池，对最大值的设定会带来很多意想不到的麻烦 &lt;br /&gt;&lt;br /&gt;线程池的线程为何要分类? &lt;br /&gt;&lt;br /&gt;线程池有一个方法可以让我们看到线程池中可用的线程数量:GetAvaliableThread(out workerThreadCount,out iocompletedThreadCount),对于我来说,第一次看到这个函数的参数时十分困惑,因为我期望这个函数直接返回一个整形,表明还剩多少线程,这个函数居然一次返回了两个变量. &lt;br /&gt;&lt;br /&gt;原来线程池里的线程按照公用被分成了两大类:工作线程和IO线程,或者IO完成线程,前者用于执行普通的操作,后者专用于异步IO,比如文件和网络请求,注意,分类并不说明两种线程本身有差别,线程就是线程,是一种执行单元,从本质上来讲都是一样的,线程池这样分类,举例来说,就好像某施工工地现在有1000把铁锹,规定其中25把给后勤部门用,其他都给施工部门,施工部门需要大量使用铁锹来挖地基(例子土了点,不过说明问题还是有效的),后勤部门用铁锹也就是铲铲雪,铲铲垃圾,给工人师傅修修临时住房,所以用量不大，显然两个部门的铁锹本身没有区别，但是这样的划分就为管理两个部门的铁锹提供了方便 &lt;br /&gt;&lt;br /&gt;线程池中两种线程分别在什么情况下被使用,二者工作原理有什么不同? &lt;br /&gt;&lt;br /&gt;下面这个例子直接说明了二者的区别,我们用一个流读出一个很大的文件(大一点操作的时间长,便于观察),然后用另一个输出流把所读出的文件的一部分写到磁盘上 &lt;br /&gt;&lt;br /&gt;我们用两种方法创建输出流,分别是 &lt;br /&gt;&lt;br /&gt;创建了一个异步的流(注意构造函数最后那个true)&lt;br /&gt;&lt;br /&gt;FileStream outputfs=new FileStream(writepath, FileMode.Create, FileAccess.Write, FileShare.None,256,true);&lt;br /&gt;&lt;br /&gt;创建了一个同步的流 &lt;br /&gt;&lt;br /&gt;FileStream outputfs = File.OpenWrite(writepath); &lt;br /&gt;&lt;br /&gt; 然后在写文件期间查看线程池的状况&lt;br /&gt;&lt;br /&gt;string readpath = "e:\\RHEL4-U4-i386-AS-disc1.iso";&lt;br /&gt;string writepath = "e:\\kakakak.iso";&lt;br /&gt;byte[] buffer = new byte[90000000];&lt;br /&gt;&lt;br /&gt;//FileStream outputfs=new FileStream(writepath, FileMode.Create, FileAccess.Write, FileShare.None,256,true);&lt;br /&gt;//Console.WriteLine("异步流");&lt;br /&gt;//创建了一个同步的流&lt;br /&gt;&lt;br /&gt;FileStream outputfs = File.OpenWrite(writepath);&lt;br /&gt;Console.WriteLine("同步流");&lt;br /&gt;&lt;br /&gt; //然后在写文件期间查看线程池的状况&lt;br /&gt;&lt;br /&gt;ShowThreadDetail("初始状态");&lt;br /&gt;&lt;br /&gt;FileStream fs = File.OpenRead(readpath);&lt;br /&gt;&lt;br /&gt;fs.BeginRead(buffer, 0, 90000000, delegate(IAsyncResult o)&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    outputfs.BeginWrite(buffer, 0, buffer.Length,&lt;br /&gt;&lt;br /&gt;    delegate(IAsyncResult o1)&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;        Thread.Sleep(1000);&lt;br /&gt;&lt;br /&gt;        ShowThreadDetail("BeginWrite的回调线程");&lt;br /&gt;&lt;br /&gt;    }, null);&lt;br /&gt;&lt;br /&gt;    Thread.Sleep(500);//this is important cause without this, this Thread and the one used for BeginRead May seem to be same one&lt;br /&gt;}, null);&lt;br /&gt;&lt;br /&gt;Console.ReadLine();&lt;br /&gt;&lt;br /&gt;public static void ShowThreadDetail(string caller)&lt;br /&gt;{&lt;br /&gt;    int IO;&lt;br /&gt;    int Worker;&lt;br /&gt;    ThreadPool.GetAvailableThreads(out Worker, out IO);&lt;br /&gt;    Console.WriteLine("Worker: {0}; IO: {1}", Worker, IO);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;输出结果&lt;br /&gt;异步流&lt;br /&gt;Worker: 500; IO: 1000&lt;br /&gt;Worker: 500; IO: 999&lt;br /&gt;同步流&lt;br /&gt;Worker: 500; IO: 1000&lt;br /&gt;Worker: 499; IO: 1000&lt;br /&gt; &lt;br /&gt;这两个构造函数创建的流都可以使用BeginWrite来异步写数据,但是二者行为不同,当使用同步的流进行异步写时,通过回调的输出我们可以看到,他使用的是工作线程,而非IO线程,而异步流使用了IO线程而非工作线程 &lt;br /&gt;&lt;br /&gt;其实当没有制定异步属性的时候,.Net实现异步IO是用一个子线程调用fs的同步Write方法来实现的,这时这个子线程会一直阻塞直到调用完成.这个子线程其实就是线程池的一个工作线程,所以我们可以看到,同步流的异步写回调中输出的工作线程数少了一,而使用异步流,在进行异步写时,采用了 IOCP方法,简单说来,就是当BeginWrite执行时,把信息传给硬件驱动程序,然后立即往下执行(注意这里没有额外的线程),而当硬件准备就绪, 就会通知线程池,使用一个IO线程来读取 &lt;br /&gt;&lt;br /&gt;.Net线程池有什么不足&lt;br /&gt;&lt;br /&gt;没有提供方法控制加入线程池的线程:一旦加入线程池,我们没有办法挂起,终止这些线程,唯一可以做的就是等他自己执行&lt;br /&gt;&lt;br /&gt;1)不能为线程设置优先级&lt;br /&gt;2)一个Process中只能有一个实例，它在各个AppDomain是共享的。ThreadPool只提供了静态方法，不仅我们自己添加进去的WorkItem使用这个Pool，而且.net framework中那些BeginXXX、EndXXX之类的方法都会使用此Pool。 &lt;br /&gt;3)所支持的Callback不能有返回值。WaitCallback只能带一个object类型的参数，没有任何返回值。&lt;br /&gt;4)不适合用在长期执行某任务的场合。我们常常需要做一个Service来提供不间断的服务（除非服务器down掉），但是使用ThreadPool并不合适。&lt;br /&gt;&lt;br /&gt;下面是另外一个网友总结的什么不需要使用线程池,我觉得挺好,引用下来&lt;br /&gt;如果您需要使一个任务具有特定的优先级。 &lt;br /&gt;如果您具有可能会长时间运行（并因此阻塞其他任务）的任务。 &lt;br /&gt;如果您需要将线程放置到单线程单元中（所有 ThreadPool 线程均处于多线程单元中）。 &lt;br /&gt;如果您需要与该线程关联的稳定标识。例如，您应使用一个专用线程来中止该线程、将其挂起或按名称发现它。&lt;br /&gt;&lt;br /&gt;锁定与同步 &lt;br /&gt;&lt;br /&gt;CLR怎样实现lock(obj)锁定? &lt;br /&gt;&lt;br /&gt;从原理上讲,lock和Syncronized Attribute都是用Moniter.Enter实现的,比如如下代码&lt;br /&gt;&lt;br /&gt;object lockobj=new object();&lt;br /&gt;lock(obj){  &lt;br /&gt;//do things &lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;在编译时,会被编译为类似 &lt;br /&gt;&lt;br /&gt;try{&lt;br /&gt;  Moniter.Enter(obj){&lt;br /&gt;   //do things&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;catch{}&lt;br /&gt;finally{&lt;br /&gt;  Moniter.Exit(obj);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;而[MethodImpl(MethodImplOptions.Synchronized)]标记为同步的方法会在编译时被lock(this)语句所环绕&lt;br /&gt;所以我们只简单探讨Moniter.Enter的实现&lt;br /&gt;&lt;br /&gt;（注:DotNet并非使用Win32API的CriticalSection来实现Moniter.Enter，不过他为托管对象提供了一个类似的结构叫做Syncblk） &lt;br /&gt;&lt;br /&gt;每个对象实例头部都有一个指针,这个指针指向的结构,包含了对象的锁定信息,当第一次使用Moniter.Enter(obj)时,这个obj对象的锁定结构就会被初时化,第二次调用Moniter.Enter时,会检验这个object的锁定结构,如果锁没有被释放,则调用会阻塞 &lt;br /&gt;&lt;br /&gt;WaitHandle是什么,他和他的派生类怎么使用 &lt;br /&gt;&lt;br /&gt;  WaitHandle是Mutex，Semaphore，EventWaitHandler，AutoResetEvent，ManualResetEvent共同的祖先，他们包装了用于同步的内核对象，也就是说是这些内核对象的托管版本。 &lt;br /&gt;&lt;br /&gt;  Mutex:类似于一个接力棒,拿到接力棒的线程才可以开始跑,当然接力棒一次只属于一个线程(Thread Affinity),如果这个线程不释放接力棒(Mutex.ReleaseMutex),那么没办法,其他所有需要接力棒运行的线程都知道能等着看热闹 &lt;br /&gt;&lt;br /&gt;Semaphore:类似于一个小桶,里面装了几个小球,凡是拿到小球就可以跑,比如指定小桶里最初有四个小球,那么开始的四个线程就可以直接拿着自己的小球开跑,但是第五个线程一看,小球被拿光了,就只好乖乖的等着有谁放一个小球到小桶里(Semophore.Release),他才能跑,但是这里的游戏规则比较特殊,我们可以随意向小桶里放入小球,也就是说我可以拿走一个小球,放回去俩,甚至一个都不拿,放回去5个,这样就有五个线程可以拿着这些小球运行了.我们可以规定小桶里有开始有几个小球(构造函数的第一个参数),也可以规定最多不能超过多少小球(构造函数的第二个参数) &lt;br /&gt;&lt;br /&gt;ManualResetEvent,AutoResetEvent可以参考http://www.cnblogs.com/uubox/archive/2007/12/18/1003953.html&lt;br /&gt;&lt;br /&gt;什么是用双锁实现Singleton,为什么要这样做,双锁检验是不安全的吗? &lt;br /&gt;&lt;br /&gt;使用双锁检验技巧来实现单件,来自于Java社区&lt;br /&gt;&lt;br /&gt;public static MySingleton Instance{&lt;br /&gt;get{&lt;br /&gt;    if(_instance!=null)}{&lt;br /&gt;        lock(_instance){&lt;br /&gt;            if(s_value==null){&lt;br /&gt;                _instance= new MySingleton();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;这样做其实是为了提高效率,比起 &lt;br /&gt;public static MySingleton Instance{ &lt;br /&gt;&lt;br /&gt;get{ &lt;br /&gt;&lt;br /&gt;lock(_instance){ &lt;br /&gt;&lt;br /&gt;if(s_value==null){ &lt;br /&gt;&lt;br /&gt;_instance= new MySingleton(); &lt;br /&gt;&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;前一种方法在instance创建的时候不需要用lock同步,从而增进了效率&lt;br /&gt;&lt;br /&gt;在java中这种技巧被证明是不安全的详细见http://www.cs.umd.edu/~pugh/java/memoryModel/&lt;br /&gt;&lt;br /&gt;但是在.Net下,这样的技巧是成立的,因为.Net使用了改进的内存模型&lt;br /&gt;&lt;br /&gt;并且在.Net下,我们可以使用LazyInit来实现单件&lt;br /&gt;&lt;br /&gt;private static readonly _instance=new MySingleton()&lt;br /&gt;&lt;br /&gt;public static MySingleton Instance{&lt;br /&gt;&lt;br /&gt;get{return _instance}&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;当第一此使用_instance时,CLR会生成这个对象,以后再访问这个字段,将会直接返回&lt;br /&gt;&lt;br /&gt;互斥对象（Mutex）,信号量(Semaphore),事件（Event）对象与lock语句的比较 &lt;br /&gt;&lt;br /&gt;首先这里所谓的事件对象不是System.Event，而是一种用于同步的内核机制 &lt;br /&gt;&lt;br /&gt;互斥对象和事件对象属于内核对象，利用内核对象进行线程同步，线程必须要在用户模式和内核模式间切换，所以一般效率很低，但利用互斥对象和事件对象这样的内核对象，可以在多个进程中的各个线程间进行同步。 &lt;br /&gt;&lt;br /&gt;lock或者Moniter是.net用一个特殊结构实现的,不涉及模式切换,也就是说工作在用户方式下，同步速度较快,但是不能跨进程同步&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;什么时候需要锁定? &lt;br /&gt;&lt;br /&gt;刚刚接触锁定的程序员往往觉得这个世界非常的危险,每个静态变量似乎都有可能产生竞争 &lt;br /&gt;&lt;br /&gt;首先锁定是解决竞争条件的,也就是多个线程同时访问某个资源,造成意想不到的结果,比如,最简单的情况,一个计数器,如果两个线程同时加一,后果就是损失了一个计数,但是频繁的锁定又可能带来性能上的消耗,还有最可怕的情况,死锁 &lt;br /&gt;&lt;br /&gt;到底什么情况下我们需要使用锁,什么情况下不用呢? &lt;br /&gt;&lt;br /&gt;只有共享资源才需要锁定&lt;br /&gt;首先,只有可以被多线程访问的共享资源才需要考虑锁定,比如静态变量,再比如某些缓存中的值,属于线程内部的变量不需要锁定 &lt;br /&gt;&lt;br /&gt;把锁定交给数据库&lt;br /&gt;数据库除了存储数据之外,还有一个重要的用途就是同步,数据库本身用了一套复杂的机制来保证数据的可靠和一致性,这就为我们节省了很多的精力.保证了数据源头上的同步,我们多数的精力就可以集中在缓存等其他一些资源的同步访问上了 &lt;br /&gt;&lt;br /&gt;了解你的程序是怎么运行的&lt;br /&gt;实际上在web开发中大多数逻辑都是在单个线程中展开的,无论asp.net还是php,一个请求都会在一个单独的线程中处理,其中的大部分变量都是属于这个线程的,根本没有必要考虑锁定,当然对于asp.net中的application对象中的数据,我们就要小心一些了&lt;br /&gt;&lt;br /&gt;WinForm中凡是使用BeginInvoke和Invoke调用的方法也都不需要考虑同步,因为这用这两个方法调用的方法会在UI线程中执行,因此实际是同步的,所以如果调用的方法中存在某些静态变量,不需要考虑锁定&lt;br /&gt;&lt;br /&gt;业务逻辑对事务和线程安全的要求&lt;br /&gt;这条是最根本的东西,开发完全线程安全的程序是件很费时费力的事情,在电子商务等涉及金融系统的案例中,许多逻辑都必须严格的线程安全,所以我们不得不牺牲一些性能,和很多的开发时间来做这方面的工作,而一般的应用中,许多情况下虽然程序有竞争的危险,我们还是可以不使用锁定,比如有的时候计数器少一多一,对结果无伤大雅的情况下,我们就可以不用去管他 &lt;br /&gt;&lt;br /&gt;计算一下冲突的可能性&lt;br /&gt;我以前曾经谈到过,架构不要过设计,其实在这里也一样,假如你的全局缓存里的某个值每天只有几百或者几千个访问,并且访问时间很短,并且分布均匀(实际上这是大多数的情况),那么冲突的可能性就非常的少,也许每500天才会出现一次或者更长,从7*24小时安全服务的角度来看,也完全符合要求,那么你还会为这样万分之一的可能性花80%的精力去设计吗? &lt;br /&gt;&lt;br /&gt;请多使用lock,少用Mutex&lt;br /&gt;如果你一定要使用锁定,请尽量不要使用内核模块的锁定机制,比如.net的Mutex,Semaphore,AutoResetEvent,ManuResetEvent,使用这样的机制涉及到了系统在用户模式和内核模式间的切换,所以性能差很多,但是他们的优点是可以跨进程同步线程,所以应该清楚的了解到他们的不同和适用范围 &lt;br /&gt;&lt;br /&gt;Web和IIS应用程序池,WebApplication,和线程池之间有什么关系&lt;br /&gt;&lt;br /&gt;一个应用程序池是一个独立的进程,拥有一个线程池,应用程序池中可以有多个WebApplication,每个运行在一个单独的AppDomain中,这些WebApplication公用一个线程池&lt;br /&gt;&lt;br /&gt;不同的AppDomain保证了每个WebApplication的静态变量不会互相干扰,不同的应用程序池保证了一个网站瘫痪,其他不同进程中的站点还能正常运行&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-8105129262071529265?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/8105129262071529265'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/8105129262071529265'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2006/12/some-notes-on-threadpool-2.html' title='Some notes on ThreadPool - 2'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-3348994659259508625</id><published>2006-12-21T23:33:00.000-08:00</published><updated>2007-05-27T23:44:46.622-07:00</updated><title type='text'>Some notes on ThreadPool - 1</title><content type='html'>We may use different words to describe the concept we will discuss below, thread pool, waiting queue, ...&lt;br /&gt;&lt;br /&gt;1.&lt;br /&gt;From http://www.cnblogs.com/jobs/archive/2007/04/27/730255.html&lt;br /&gt;&lt;br /&gt;精巧好用的DelayQueue &lt;br /&gt;&lt;br /&gt;我们谈一下实际的场景吧。我们在开发中，有如下场景&lt;br /&gt;&lt;br /&gt;a) 关闭空闲连接。服务器中，有很多客户端的连接，空闲一段时间之后需要关闭之。&lt;br /&gt;b) 缓存。缓存中的对象，超过了空闲时间，需要从缓存中移出。&lt;br /&gt;c) 任务超时处理。在网络协议滑动窗口请求应答式交互时，处理超时未响应的请求。&lt;br /&gt;&lt;br /&gt;一种笨笨的办法就是，使用一个后台线程，遍历所有对象，挨个检查。这种笨笨的办法简单好用，但是对象数量过多时，可能存在性能问题，检查间隔时间不好设置，间隔时间过大，影响精确度，多小则存在效率问题。而且做不到按超时的时间顺序处理。 &lt;br /&gt;&lt;br /&gt;这场景，使用DelayQueue最适合了。&lt;br /&gt;&lt;br /&gt;DelayQueue是java.util.concurrent中提供的一个很有意思的类。很巧妙，非常棒！但是java doc和Java SE 5.0的source中都没有提供Sample。我最初在阅读ScheduledThreadPoolExecutor源码时，发现DelayQueue的妙用。随后在实际工作中，应用在session超时管理，网络应答通讯协议的请求超时处理。&lt;br /&gt;&lt;br /&gt;本文将会对DelayQueue做一个介绍，然后列举应用场景。并且提供一个Delayed接口的实现和Sample代码。&lt;br /&gt;&lt;br /&gt;DelayQueue是一个BlockingQueue，其特化的参数是Delayed。（不了解BlockingQueue的同学，先去了解BlockingQueue再看本文）&lt;br /&gt;Delayed扩展了Comparable接口，比较的基准为延时的时间值，Delayed接口的实现类getDelay的返回值应为固定值（final）。DelayQueue内部是使用PriorityQueue实现的。&lt;br /&gt;&lt;br /&gt;DelayQueue = BlockingQueue + PriorityQueue + Delayed&lt;br /&gt;&lt;br /&gt;DelayQueue的关键元素BlockingQueue、PriorityQueue、Delayed。可以这么说，DelayQueue是一个使用优先队列（PriorityQueue）实现的BlockingQueue，优先队列的比较基准值是时间。&lt;br /&gt;&lt;br /&gt;他们的基本定义如下&lt;br /&gt;public interface Comparable&lt;T&gt; {&lt;br /&gt;    public int compareTo(T o);&lt;br /&gt;}&lt;br /&gt;public interface Delayed extends Comparable&lt;Delayed&gt; {&lt;br /&gt;    long getDelay(TimeUnit unit);&lt;br /&gt;}&lt;br /&gt;public class DelayQueue&lt;E extends Delayed&gt; implements BlockingQueue&lt;E&gt; { &lt;br /&gt;    private final PriorityQueue&lt;E&gt; q = new PriorityQueue&lt;E&gt;();&lt;br /&gt;}&lt;br /&gt;DelayQueue内部的实现使用了一个优先队列。当调用DelayQueue的offer方法时，把Delayed对象加入到优先队列q中。如下：&lt;br /&gt;public boolean offer(E e) {&lt;br /&gt;    final ReentrantLock lock = this.lock;&lt;br /&gt;    lock.lock();&lt;br /&gt;    try {&lt;br /&gt;        E first = q.peek();&lt;br /&gt;        q.offer(e);&lt;br /&gt;        if (first == null || e.compareTo(first) &lt; 0)&lt;br /&gt;            available.signalAll();&lt;br /&gt;        return true;&lt;br /&gt;    } finally {&lt;br /&gt;        lock.unlock();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;DelayQueue的take方法，把优先队列q的first拿出来（peek），如果没有达到延时阀值，则进行await处理。如下：&lt;br /&gt;public E take() throws InterruptedException {&lt;br /&gt;    final ReentrantLock lock = this.lock;&lt;br /&gt;    lock.lockInterruptibly();&lt;br /&gt;    try {&lt;br /&gt;        for (;;) {&lt;br /&gt;            E first = q.peek();&lt;br /&gt;            if (first == null) {&lt;br /&gt;                available.await();&lt;br /&gt;            } else {&lt;br /&gt;                long delay =  first.getDelay(TimeUnit.NANOSECONDS);&lt;br /&gt;                if (delay &gt; 0) {&lt;br /&gt;                    long tl = available.awaitNanos(delay);&lt;br /&gt;                } else {&lt;br /&gt;                    E x = q.poll();&lt;br /&gt;                    assert x != null;&lt;br /&gt;                    if (q.size() != 0)&lt;br /&gt;                        available.signalAll(); // wake up other takers&lt;br /&gt;                    return x;&lt;br /&gt;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    } finally {&lt;br /&gt;        lock.unlock();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;-------------------&lt;br /&gt;&lt;br /&gt;以下是Sample，是一个缓存的简单实现。共包括三个类Pair、DelayItem、Cache。如下：&lt;br /&gt;&lt;br /&gt;public class Pair&lt;K, V&gt; {&lt;br /&gt;    public K first;&lt;br /&gt;&lt;br /&gt;    public V second;&lt;br /&gt;    &lt;br /&gt;    public Pair() {}&lt;br /&gt;    &lt;br /&gt;    public Pair(K first, V second) {&lt;br /&gt;        this.first = first;&lt;br /&gt;        this.second = second;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;--------------&lt;br /&gt;以下是Delayed的实现&lt;br /&gt;import java.util.concurrent.Delayed;&lt;br /&gt;import java.util.concurrent.TimeUnit;&lt;br /&gt;import java.util.concurrent.atomic.AtomicLong;&lt;br /&gt;&lt;br /&gt;public class DelayItem&lt;T&gt; implements Delayed {&lt;br /&gt;    /** Base of nanosecond timings, to avoid wrapping */&lt;br /&gt;    private static final long NANO_ORIGIN = System.nanoTime();&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Returns nanosecond time offset by origin&lt;br /&gt;     */&lt;br /&gt;    final static long now() {&lt;br /&gt;        return System.nanoTime() - NANO_ORIGIN;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * Sequence number to break scheduling ties, and in turn to guarantee FIFO order among tied&lt;br /&gt;     * entries.&lt;br /&gt;     */&lt;br /&gt;    private static final AtomicLong sequencer = new AtomicLong(0);&lt;br /&gt;&lt;br /&gt;    /** Sequence number to break ties FIFO */&lt;br /&gt;    private final long sequenceNumber;&lt;br /&gt;&lt;br /&gt;    /** The time the task is enabled to execute in nanoTime units */&lt;br /&gt;    private final long time;&lt;br /&gt;&lt;br /&gt;    private final T item;&lt;br /&gt;&lt;br /&gt;    public DelayItem(T submit, long timeout) {&lt;br /&gt;        this.time = now() + timeout;&lt;br /&gt;        this.item = submit;&lt;br /&gt;        this.sequenceNumber = sequencer.getAndIncrement();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public T getItem() {&lt;br /&gt;        return this.item;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public long getDelay(TimeUnit unit) {&lt;br /&gt;        long d = unit.convert(time - now(), TimeUnit.NANOSECONDS);&lt;br /&gt;        return d;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int compareTo(Delayed other) {&lt;br /&gt;        if (other == this) // compare zero ONLY if same object&lt;br /&gt;            return 0;&lt;br /&gt;        if (other instanceof DelayItem) {&lt;br /&gt;            DelayItem x = (DelayItem) other;&lt;br /&gt;            long diff = time - x.time;&lt;br /&gt;            if (diff &lt; 0)&lt;br /&gt;                return -1;&lt;br /&gt;            else if (diff &gt; 0)&lt;br /&gt;                return 1;&lt;br /&gt;            else if (sequenceNumber &lt; x.sequenceNumber)&lt;br /&gt;                return -1;&lt;br /&gt;            else&lt;br /&gt;                return 1;&lt;br /&gt;        }&lt;br /&gt;        long d = (getDelay(TimeUnit.NANOSECONDS) - other.getDelay(TimeUnit.NANOSECONDS));&lt;br /&gt;        return (d == 0) ? 0 : ((d &lt; 0) ? -1 : 1);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;以下是Cache的实现，包括了put和get方法，还包括了可执行的main函数。&lt;br /&gt;import java.util.concurrent.ConcurrentHashMap;&lt;br /&gt;import java.util.concurrent.ConcurrentMap;&lt;br /&gt;import java.util.concurrent.DelayQueue;&lt;br /&gt;import java.util.concurrent.TimeUnit;&lt;br /&gt;import java.util.logging.Level;&lt;br /&gt;import java.util.logging.Logger;&lt;br /&gt;&lt;br /&gt;public class Cache&lt;K, V&gt; {&lt;br /&gt;    private static final Logger LOG = Logger.getLogger(Cache.class.getName());&lt;br /&gt;&lt;br /&gt;    private ConcurrentMap&lt;K, V&gt; cacheObjMap = new ConcurrentHashMap&lt;K, V&gt;();&lt;br /&gt;&lt;br /&gt;    private DelayQueue&lt;DelayItem&lt;Pair&lt;K, V&gt;&gt;&gt; q = new DelayQueue&lt;DelayItem&lt;Pair&lt;K, V&gt;&gt;&gt;();&lt;br /&gt;&lt;br /&gt;    private Thread daemonThread;&lt;br /&gt;&lt;br /&gt;    public Cache() {&lt;br /&gt;&lt;br /&gt;        Runnable daemonTask = new Runnable() {&lt;br /&gt;            public void run() {&lt;br /&gt;                daemonCheck();&lt;br /&gt;            }&lt;br /&gt;        };&lt;br /&gt;&lt;br /&gt;        daemonThread = new Thread(daemonTask);&lt;br /&gt;        daemonThread.setDaemon(true);&lt;br /&gt;        daemonThread.setName("Cache Daemon");&lt;br /&gt;        daemonThread.start();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void daemonCheck() {&lt;br /&gt;&lt;br /&gt;        if (LOG.isLoggable(Level.INFO))&lt;br /&gt;            LOG.info("cache service started.");&lt;br /&gt;&lt;br /&gt;        for (;;) {&lt;br /&gt;            try {&lt;br /&gt;                DelayItem&lt;Pair&lt;K, V&gt;&gt; delayItem = q.take();&lt;br /&gt;                if (delayItem != null) {&lt;br /&gt;                    // 超时对象处理&lt;br /&gt;                    Pair&lt;K, V&gt; pair = delayItem.getItem();&lt;br /&gt;                    cacheObjMap.remove(pair.first, pair.second); // compare and remove&lt;br /&gt;                }&lt;br /&gt;            } catch (InterruptedException e) {&lt;br /&gt;                if (LOG.isLoggable(Level.SEVERE))&lt;br /&gt;                    LOG.log(Level.SEVERE, e.getMessage(), e);&lt;br /&gt;                break;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        if (LOG.isLoggable(Level.INFO))&lt;br /&gt;            LOG.info("cache service stopped.");&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // 添加缓存对象&lt;br /&gt;    public void put(K key, V value, long time, TimeUnit unit) {&lt;br /&gt;        V oldValue = cacheObjMap.put(key, value);&lt;br /&gt;        if (oldValue != null)&lt;br /&gt;            q.remove(key);&lt;br /&gt;&lt;br /&gt;        long nanoTime = TimeUnit.NANOSECONDS.convert(time, unit);&lt;br /&gt;        q.put(new DelayItem&lt;Pair&lt;K, V&gt;&gt;(new Pair&lt;K, V&gt;(key, value), nanoTime));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public V get(K key) {&lt;br /&gt;        return cacheObjMap.get(key);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // 测试入口函数&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        Cache&lt;Integer, String&gt; cache = new Cache&lt;Integer, String&gt;();&lt;br /&gt;        cache.put(1, "aaaa", 3, TimeUnit.SECONDS);&lt;br /&gt;&lt;br /&gt;        Thread.sleep(1000 * 2);&lt;br /&gt;        {&lt;br /&gt;            String str = cache.get(1);&lt;br /&gt;            System.out.println(str);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        Thread.sleep(1000 * 2);&lt;br /&gt;        {&lt;br /&gt;            String str = cache.get(1);&lt;br /&gt;            System.out.println(str);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;运行Sample，main函数执行的结果是输出两行，第一行为aaa，第二行为null。&lt;br /&gt;&lt;br /&gt;2.&lt;br /&gt;源代码直接看rotor&lt;br /&gt;http://dotnet.di.unipi.it/Content/sscli/docs/doxygen/clr/vm/win32threadpool_8h.html&lt;br /&gt;http://dotnet.di.unipi.it/Content/sscli/docs/doxygen/clr/vm/win32threadpool_8h-source.html&lt;br /&gt;&lt;br /&gt;看到了const int  MaxLimitCPThreadsPerCPU = 25 这样的直白要求。不过我觉得还是计算TLS时间来确定比较科学一些。慢慢来了。&lt;br /&gt;&lt;br /&gt;没有分析mono是怎么实现的&lt;br /&gt;&lt;br /&gt;3.&lt;br /&gt;.NET's ThreadPool Class - Behind The Scenes&lt;br /&gt;By Marc Clifton （按：赞，又是他老人家）&lt;br /&gt;http://www.codeproject.com/csharp/threadtests.asp&lt;br /&gt;&lt;br /&gt;这个总结得真好，流程图一目了然&lt;br /&gt;&lt;br /&gt;4.&lt;br /&gt;Threads&lt;br /&gt;http://threads.sourceforge.net/&lt;br /&gt;这个库似乎是给Linux用的。&lt;br /&gt;&lt;br /&gt;5.&lt;br /&gt;ZThreads&lt;br /&gt;http://zthread.sourceforge.net/&lt;br /&gt;跨平台的C++线程和同步库。为了跨平台，有的地方写的好麻烦。&lt;br /&gt;&lt;br /&gt;6.&lt;br /&gt;然后是学习ACE＋TAO＋RTCOBRA的Lane思想，其根据地的说明肯定要看。该文档由Doxygen产生的，非常漂亮。&lt;br /&gt;http://www.dre.vanderbilt.edu/Doxygen/Current/html/tao/rtcorba/hierarchy.html&lt;br /&gt;http://www.dre.vanderbilt.edu/Doxygen/Current/html/tao/rtcorba/classTAO__Thread__Lane.html&lt;br /&gt;http://www.dre.vanderbilt.edu/Doxygen/Current/html/tao/rtcorba/classTAO__Thread__Pool.html&lt;br /&gt;&lt;br /&gt;7.&lt;br /&gt;这里还有个简单的ThreadpoolwithLane中文说明和一些Java资源&lt;br /&gt;http://www.huihoo.org/rt/RTThreadPool.html &lt;br /&gt;&lt;br /&gt;RTThreadPool设计分析&lt;br /&gt;&lt;br /&gt;(by huihoo.org Cocia Lin(cocia@163.com)) &lt;br /&gt;&lt;br /&gt;概述&lt;br /&gt;实时系统中的线程池，需要考虑的特性，主要有以下几点： &lt;br /&gt;1．初始服务线程数量，动态增加线程数量 &lt;br /&gt;2．预分配线程池占用内存空间 &lt;br /&gt;3．请求缓存，缓存请求按照优先级排队 &lt;br /&gt;4．预估线程常用优先级，配备这些优先级的独立优先级线程池。也就是配置通道(Lane)的线程池 &lt;br /&gt;5．线程池销毁，释放资源 &lt;br /&gt;&lt;br /&gt;实时线程池的这些特性，重点围绕在线程资源控制，优先级控制。 &lt;br /&gt;&lt;br /&gt;在通用的非实时系统中，Doug Lea的util.conconrrenct同步线程开发包定义了很优美的结构模型和提供了基本的线程池实现。util.conconrrenct相关的内容，请自行参考。 &lt;br /&gt;&lt;br /&gt;从非实时的角度来看，Doug Lea提供的线程池实现，已经很完善。但是对于实时系统中，他缺少主要的实时特性。所以我的想法是，在非实时线程池上进行扩展，使他具备实时特性。 &lt;br /&gt;&lt;br /&gt;非实时线程池中不用修改，就可以被实时线程池利用的功能有以下几点： &lt;br /&gt;1．初始服务线程数量，动态增加线程数量 &lt;br /&gt;2．请求缓存排队 &lt;br /&gt;&lt;br /&gt;对非实时线程池不具备的实时特性，有以下几点： &lt;br /&gt;1．请求缓存按照优先级排队 &lt;br /&gt;2．指定任务的执行的线程优先级 &lt;br /&gt;3．配置通道(Lane)的线程池 &lt;br /&gt;4．预分配线程池占用内存空间（暂时不讨论这一点） &lt;br /&gt;&lt;br /&gt;针对在非实时线程池之上扩展实时线程池，我们现在来一一讨论。 &lt;br /&gt;&lt;br /&gt;请求缓存按照优先级排队&lt;br /&gt;我们先来看看在非实时线程池中，请求的处理时，如果队列中因为线程池没有足够的就绪线程，就需要等待，将请求暂时放置在请求队列中。而这时，可能有很多请求不断添加到请求队列中，队列中的请求任务，也是不分优先级，按照入队的顺序排列。当线程池中有空闲的线程时，在队首的第一个请求任务会首先得到运行，而不是队列中的优先级最高的任务。这就出现了优先级低的任务比优先级高的任务抢先得到运行的情况，叫做优先级翻转。这种情况，需要在实时系统中尽量避免的。 &lt;br /&gt;&lt;br /&gt;解决的方法，就是在等待运行的请求队列中，实现根据优先级排队的队列。当一个请求任务被放入队列中时，如果发现，在他之前，有低的优先级任务存在，那么，高优先级任务就会向前移动，直到他前面的优先级都没有他低为止。 &lt;br /&gt;&lt;br /&gt;Util.conconrrent同步工具包中，队列的抽象叫做Channel。并且提供了几种队列实现，但是其中没有排序队列，这就需要我们自己来实现PriorityChannel。实现代码请见参考。 &lt;br /&gt;&lt;br /&gt;有了优先级排序的队列，取代非实时线程池中的请求队列，就实现了请求缓存按照优先级排队。 &lt;br /&gt;&lt;br /&gt;指定任务的执行的线程优先级&lt;br /&gt;非实时线程池中的线程，都是默认优先级的，而且都是一样优先级的。所以在任务被执行的时候，cpu时间的抢占，内存资源，网络资源等，都是按照这个默认优先级分配的。无法指定任务运行时的优先级，是无法满足实时要求的。看一下下面的代码： &lt;br /&gt;&lt;br /&gt;用户： &lt;br /&gt;PooledExecutor pool = new PooledExecutor(20); &lt;br /&gt;pool.execute(new Runnable() { &lt;br /&gt;public void run() { &lt;br /&gt;process(connection); &lt;br /&gt;}}); &lt;br /&gt;&lt;br /&gt;线程池内部： &lt;br /&gt;while ( (task = getTaskFromQueue()) != null) { &lt;br /&gt; task.run(); &lt;br /&gt; task = null; &lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;在pool.execute()方法被调用时，将指定的任务放入请求等待队列，准备运行。然后，线程池的监护线程监测到有新任务到达，就会从请求队列中取出任务，运行。但是，任务是以运行任务的线程优先级运行的。这样就没有体现任何的优先级分别。 &lt;br /&gt;&lt;br /&gt;现在，需要把任务放入请求队列时的优先级纪录下来，任务在运行的时候，根据这个优先级，改变运行的优先级级别，任务运行完成后，再还原线程优先级。 &lt;br /&gt;&lt;br /&gt;while ( (task = getTask()) != null) { &lt;br /&gt; //Change current thread priority to the priority of task. &lt;br /&gt; RTRunnable rttask = (RTRunnable)task; &lt;br /&gt; int oldprio = setCurrentThreadPriority(rttask.getPriority()); &lt;br /&gt; //run the task. &lt;br /&gt; task.run(); &lt;br /&gt; task = null; &lt;br /&gt; rttask = null; &lt;br /&gt; //priority change back. &lt;br /&gt;setCurrentThreadPriority(oldprio); &lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;这样，线程池就可以根据请求任务的线程优先级，执行请求任务了。 &lt;br /&gt;&lt;br /&gt;配置通道(Lane)的线程池&lt;br /&gt;线程池通道(Thread Lane)的概念，出自RT-CORBA规范。但是，这样的线程池形式，对所有的实时系统都很有用。 &lt;br /&gt;&lt;br /&gt;线程池通道设计的出发点是：在线程池中，分成许多小的线程池，这些小的线程池，都指定了相应的优先级，当一个请求到达的时候，按照请求的优先级，直接将请求交给对应的那个小的线程池中运行 &lt;br /&gt;&lt;br /&gt;看看下面的例子，当有一个优先级为15的请求任务，要求被执行，就会根据优先级匹配，将这个任务交给Lane2(15)来运行。 如果有一个优先级为13的请求任务到达后，怎么处理呢？线程池会根据优先级最接近的原则，找到Lane2(15),然后取出一个就绪线程，将此线程优先级调整到请求任务要求的优先级，然后运行。 &lt;br /&gt;&lt;br /&gt;对于用户来说，用户看到得是这个大的线程池，内部的Lane对用户并不可见。当Lane2(15)中已经没有多余的线程了，而其他小的线程池中还有线程。这时用户的请求任务会被阻塞。为了优化线程池，允许线程借调行为。当当前Lane中没有多余线程可用，可以从比他优先级低的Lane中借取线程，升高借来的线程的优先级，运行请求任务。运行完成后，还原线程优先级，退还线程。当所有被他低的Lane中都没有可用线程，这时用户的请求任务才会被阻塞。（按：这个实现比较烦人） &lt;br /&gt;&lt;br /&gt;以上描述了带通道的线程池的行为方式。如果将这个线程池退化到只有一个Lane的时候，这个线程池就等价于不带Lane的线程池。所以，只要实现带通道的线程池，我们通过对Lane的设置，就可以得到带Lane的和不带Lane的线程池。实际上，我们也是这样做的。 &lt;br /&gt;&lt;br /&gt;将前面我们改造过的线程池，作为我们线程池中的Lane，再根据用户的请求任务，为请求任务匹配合适的Lane，再把任务交给具体的Lane运行，就可以了。 &lt;br /&gt;&lt;br /&gt;结束&lt;br /&gt;上面，对实时线程池的分析和实现进行了讨论。具体的实现代码可以参见后面参考。上面讨论的内容，关于内存的分配没有涉及，因为这可能涉及到更多的内容。所以现阶段先不考虑这个问题。 &lt;br /&gt;&lt;br /&gt;对于上面的内容，希望大家能够交流和讨论。以资进步。 &lt;br /&gt;&lt;br /&gt;参考&lt;br /&gt;开放企业基金会 &lt;br /&gt;http://www.huihoo.org &lt;br /&gt;&lt;br /&gt;orbas是开放源码的一个Java CORBA的实现，对RT-CORBA进行支持。 &lt;br /&gt;本文描述的实时线程吃，包含在orbas源码中。 &lt;br /&gt;http://www.huihoo.org/orbas/index.html &lt;br /&gt;&lt;br /&gt;Doug Lea的util.conconrrenct同步线程开发包 &lt;br /&gt;http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html &lt;br /&gt;&lt;br /&gt;Real-Time Java Expert Group &lt;br /&gt;http://www.rtj.org &lt;br /&gt;&lt;br /&gt;基于Jrate的rtsj RT-ORB:ZEN &lt;br /&gt;http://www.zen.uci.edu/ &lt;br /&gt;&lt;br /&gt;好了，接下来分析我们需要加些什么。首先我们需要ThreadID。在DotNet Threadpool，ThreadID是不重视的。Rotor中写到&lt;br /&gt;&lt;br /&gt;threadCB-&gt;threadId = threadId;    // may be useful for debugging otherwise not used&lt;br /&gt;&lt;br /&gt;而我们需要一个ID。简单的想法是产生一个自动增长的Unsigned整数ID，然后循环使用。于是我们看到有人这么写&lt;br /&gt;&lt;br /&gt;this-&gt;m_ID = InterlockedIncrement(&amp;LastUsedID);&lt;br /&gt;&lt;br /&gt;可是，这依然是不太安全的。参见Raymond Chen的blog&lt;br /&gt;Interlocked operations don't solve everything &lt;br /&gt;http://weblogs.asp.net/oldnewthing/archive/2004/09/15/229915.aspx&lt;br /&gt;&lt;br /&gt;Interlocked operations are a high-performance way of updating DWORD-sized or pointer-sized values in an atomic manner. Note, however, that this doesn't mean that you can avoid the critical section. &lt;br /&gt;&lt;br /&gt;For example, suppose you have a critical section that protects a variable, and in some other part of the code, you want to update the variable atomically. "Well," you say, "this is a simple imcrement, so I can skip the critical section and just do a direct InterlockedIncrement. Woo-hoo, I avoided the critical section bottleneck." &lt;br /&gt;&lt;br /&gt;Well, except that the purpose of that critical section was to ensure that nobody changed the value of the variable while the protected section of code was running. You just ran in and changed the value behind that code's back. &lt;br /&gt;&lt;br /&gt;Conversely, some people suggested emulating complex interlocked operations by having a critical section whose job it was to protect the variable. For example, you might have an InterlockedMultiply that goes like this: &lt;br /&gt;&lt;br /&gt;// Wrong!&lt;br /&gt;LONG InterlockedMultiply(volatile LONG *plMultiplicand, LONG lMultiplier)&lt;br /&gt;{&lt;br /&gt;  EnterCriticalSection(&amp;SomeCriticalSection);&lt;br /&gt;  LONG lResult = *plMultiplicand *= lMultiplier;&lt;br /&gt;  LeaveCriticalSection(&amp;SomeCriticalSection);&lt;br /&gt;  return lResult;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;While this code does protect against two threads performing an InterlockedMultiply against the same variable simultaneously, it fails to protect against other code performing a simple atomic write to the variable. Consider the following: &lt;br /&gt;&lt;br /&gt;int x = 2;&lt;br /&gt;Thread1()&lt;br /&gt;{&lt;br /&gt;  InterlockedIncrement(&amp;x);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Thread2()&lt;br /&gt;{&lt;br /&gt;  InterlockedMultiply(&amp;x, 5);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;If the InterlockedMultiply were truly interlocked, the only valid results would be x=15 (if the interlocked increment beat the interlocked multiply) or x=11 (if the interlocked multiply beat the interlocked increment). But since it isn't truly interlocked, you can get other weird values: &lt;br /&gt;&lt;br /&gt;Thread 1 Thread 2 &lt;br /&gt;x = 2 at start &lt;br /&gt; InterlockedMultiply(&amp;x, 5) &lt;br /&gt; EnterCriticalSection &lt;br /&gt; load x (loads 2) &lt;br /&gt;InterlockedIncrement(&amp;x);&lt;br /&gt;x is now 3  &lt;br /&gt; multiply by 5 (result: 10) &lt;br /&gt; store x (stores 10) &lt;br /&gt; LeaveCriticalSection &lt;br /&gt;x = 10 at end &lt;br /&gt;&lt;br /&gt;Oh no, our interlocked multiply isn't very interlocked after all! How can we fix it? &lt;br /&gt;&lt;br /&gt;If the operation you want to perform is a function solely of the starting numerical value and the other function parameters (with no dependencies on any other memory locations), you can write your own interlocked-style operation with the help of InterlockedCompareExchange. &lt;br /&gt;&lt;br /&gt;LONG InterlockedMultiply(volatile LONG *plMultiplicand, LONG lMultiplier)&lt;br /&gt;{&lt;br /&gt;  LONG lOriginal, lResult;&lt;br /&gt;  do {&lt;br /&gt;    lOriginal = *plMultiplicand;&lt;br /&gt;    lResult = lOriginal * lMultiplier;&lt;br /&gt;  } while (InterlockedCompareExchange(plMultiplicand,&lt;br /&gt;                                      lResult, lOriginal) != lOriginal);&lt;br /&gt;  return lResult;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[Typo in algorithm fixed 9:00am.] &lt;br /&gt;&lt;br /&gt;To perform a complicated function on the multiplicand, we perform three steps. &lt;br /&gt;&lt;br /&gt;First, capture the value from memory: lOriginal = *plMultiplicand; &lt;br /&gt;&lt;br /&gt;Second, compute the desired result from the captured value: lResult = lOriginal * lMultiplier; &lt;br /&gt;&lt;br /&gt;Third, store the result provided the value in memory has not changed: InterlockedCompareExchange(plMultiplicand, lResult, lOriginal) &lt;br /&gt;&lt;br /&gt;If the value did change, then this means that the interlocked operation was unsucessful because somebody else changed the value while we were busy doing our computation. In that case, loop back and try again. &lt;br /&gt;&lt;br /&gt;If you walk through the scenario above with this new InterlockedMultiply function, you will see that after the interloping InterlockedIncrement, the loop will detect that the value of "x" has changed and restart. Since the final update of "x" is performed by an InterlockedCompareExchange operation, the result of the computation is trusted only if "x" did not change value. &lt;br /&gt;&lt;br /&gt;Note that this technique works only if the operation being performed is a pure function of the memory value and the function parameters. If you have to access other memory as part of the computation, then this technique will not work! That's because those other memory locations might have changed during the computation and you would have no way of knowing, since InterlockedCompareExchange checks only the memory value being updated. &lt;br /&gt;&lt;br /&gt;Failure to heed the above note results in problems such as the so-called "ABA Problem". I'll leave you to google on that term and read about it. Fortunately, everybody who talks about it also talks about how to solve the ABA Problem, so I'll leave you to read that, too. &lt;br /&gt;&lt;br /&gt;Once you've read about the ABA Problem and its solution, you should be aware that the solution has already been implemented for you, via the Interlocked SList functions. &lt;br /&gt;&lt;br /&gt;所以说，我们还是需要CriticalSection。当然，我们应该把这个CriticalSection分给Lane或者更上一层的Pool。于是把其定义成friend function吧。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-3348994659259508625?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/3348994659259508625'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/3348994659259508625'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2006/12/some-notes-on-threadpool-1.html' title='Some notes on ThreadPool - 1'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-2402646752586016395</id><published>2006-12-16T20:22:00.000-08:00</published><updated>2009-04-14T20:23:42.393-07:00</updated><title type='text'>Some notes on IE8 Programming - 1</title><content type='html'>1.&lt;br /&gt;from http://blog.csdn.net/WinGeek/archive/2009/02/01/3856044.aspx&lt;br /&gt;&lt;br /&gt;Session cookie 被广泛用来做用户身份校验。 相比IE7， IE8的Session 管理有很大变化， 这是Web 开发者需要注意的。&lt;br /&gt;&lt;br /&gt;IE7中，同一个窗口(IE 进程）共享一个session。 &lt;br /&gt;&lt;br /&gt;IE8中，所有打开的IE窗口（IE 进程）共享一个session。除非，用户通过菜单 File &gt; New session  打开新窗口，或者使用命令行参数 iexplore.exe -nomerge 来打开IE。  另外，当所有IE窗口被关闭后，session 结束。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-2402646752586016395?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/2402646752586016395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/2402646752586016395'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2006/12/some-notes-on-ie8-programming-1.html' title='Some notes on IE8 Programming - 1'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-116546526689059240</id><published>2006-12-15T20:18:00.000-08:00</published><updated>2006-12-06T21:57:43.230-08:00</updated><title type='text'>Some notes on IE7 Programming - 1</title><content type='html'>1.&lt;br /&gt;如何避免IE7中Zoom功能放大滚动条 &lt;br /&gt;&lt;br /&gt;from http://www.cnblogs.com/birdshome/archive/2006/11/26/ie7_zoom.html&lt;br /&gt;&lt;br /&gt;   由于现在显示器越来越大17'、19'甚至20'都很普通了，并且显示器的分辨率也越来越高，使用1280x1024的用户已经高于使用800x600的用户(根据本站统计)。原有的大量为800x600 9pt字体以及一些为1024x768 9pt字体设计的网页已经非常过时了。所以Zoom功能逐渐成为了浏览器的必备功能。&lt;br /&gt;&lt;br /&gt;    这个功能我最早是在Opera中看到的（但我并不知道是哪种浏览器最先提供），当时也就是为了用它来对付9pt蚂蚁字体网页，不过由于那时Opera对IE中显示完好的网页问题比较大，用了一段时间就没怎么用了，或者只是偶尔用用。后来使用Firefox，发现FF也提供了这个功能，不过FF的Zoom功能和Opera提供的Zoom功能效果是不同的。Opera的Zoom功能是对页面做按比例放大，就是说我们看到的放大页面就像是在放大镜下看到的效果一样。而FF提供的Zoom功能类似IE的字缩放，但又有所不同（IE是真正的文字缩放，而且只能缩放没有使用CSS限制的默认字体的大小）。FF的字体缩放不管字体是否使用CSS定义，都可以被缩放，并且除了图片外，文本框、复选框以及下拉列表框等控件也会被缩放。&lt;br /&gt;&lt;br /&gt;    这两种缩放各有优势，不能说谁特别好，也不能说谁特别差。只是Opera的Zoom方式比较适合对付将网页宽度定死为适合800x600或1024x768的页面，而Firefox的Zoom适合对付页面宽度根据浏览器宽度自动填充的页面。在这个Zoom功能方面，IE7之前的IE做的那是一个差劲啊。由于大多数网页都使用CSS定义字体的大小，所以IE提供的那5个Level的字体大小控制，几乎没有任何实用价值。当然目前值得大家高兴的是，IE7提供了Zoom功能。&lt;br /&gt;&lt;br /&gt;    IE7提供了类似Opera那样的Zoom功能，可是不知道IE在搞什么飞机，Zoom页面的同时，有很大一部分网页的滚动条也会被同时Zoom:(。本blog首页被Zoom in 400%后的效果如下：&lt;br /&gt;    &lt;br /&gt;    // 这滚动条也被放大的效果让人相当伤感。。。&lt;br /&gt;&lt;br /&gt;    通过简单研究，原来IE7提供的这个Zoom功能是受doctype定义影响的。像我们博客园中每位blogger自己的首页使用的doctype是：&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"&gt;，这时页面的滚动条就会被一起Zoom。而博客园首页和管理页面中的doctype是：&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"&gt;，这时页面滚动条就不会被Zoom。&lt;br /&gt;&lt;br /&gt;    除了标示出dtd文件的URL外，其实只需要修改DTD的类型就可以避免滚动条被Zoom，比如最简单删掉Transitional限制：&lt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 //EN"&gt;，这样就可以了。至于到底IE7组要怎么要的doctype，这个我目前还没有找到正式的文档。&lt;br /&gt;&lt;br /&gt;2.&lt;br /&gt;IE7 正式发布版不支持offsetheight,clientheight,scrollheight属性 &lt;br /&gt;&lt;br /&gt;from http://www.cnblogs.com/patrick/archive/2006/11/02/547462.html&lt;br /&gt;&lt;br /&gt;这两天在测试程序在IE7的兼容性，发现原来在IE6显示正常的布局，在IE7下完全乱了。&lt;br /&gt;前一阵用IE7 测试版还显示正常。&lt;br /&gt;通过跟踪javascript,发现&lt;br /&gt;document.body.offsetHeight&lt;br /&gt;根本取不到值，又试了clientHeight也取不到值。&lt;br /&gt;&lt;br /&gt;不知道是IE7正式版的bug, 还是有其他新的方法，不再支持这些属性。&lt;br /&gt;&lt;br /&gt;那位朋友知道，提示一下。&lt;br /&gt;&lt;br /&gt;谢谢 &lt;br /&gt;&lt;br /&gt;将页面的doctype从&lt;br /&gt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&lt;br /&gt;换成&lt;br /&gt;!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" &lt;br /&gt;可以取道offsetHeight 值&lt;br /&gt;&lt;br /&gt;我的程序用vs2005开发，页面上的控件尺寸，字大小就全乱了，得从新调整 &lt;br /&gt;&lt;br /&gt;# re: IE7 正式发布版不支持offsetheight,clientheight,scrollheight属性  回复  更多评论    &lt;br /&gt;2006-11-02 12:51 by ddee &lt;br /&gt;这个问题我前段时间也遇到了的，而且ie7的rc2也没有问题，但是在正式版中就存在问题了。 &lt;br /&gt;&lt;br /&gt;后来我是在css显示指定了每个样式的position，特别是body，就没有问题了。可能是7.0正式版对默认值上支持的问题&lt;br /&gt;&lt;br /&gt;3.&lt;br /&gt;From http://blog.joycode.com/jiangsheng/archive/2006/10/28/85822.aspx&lt;br /&gt;&lt;br /&gt;Building Browser Helper Objects with Visual Studio 2005 &lt;br /&gt;尽管BHO被给与了太多的权限，以至于很多反恶意软件对BHO倍加关注，但是很多BHO也是很有用的，例如Google ToolBar和Internet Explorer Developer Toolbar。在Windows XP SP2中，微软在IE中加入了加载项管理器来管理包含BHO在内的浏览器扩展。&lt;br /&gt;&lt;br /&gt;微软在1999年1月发布了一篇名为Browser Helper Objects: The Browser the Way You Want It的文章，同时在微软知识库中也提供了一个示例IEHelper，这使得编写BHO的难度大大降低，但是这也使得有缺陷的BHO的数量增加。甚至在最近这篇文章Building Browser Helper Objects with Visual Studio 2005的示例代码中，也有着一些缺陷，但是这篇文章也详尽地阐述了编写BHO需要注意的事项，编写BHO的程序员应该去看一看。&lt;br /&gt;&lt;br /&gt;文中的RGS应该从&lt;br /&gt;&lt;br /&gt;HKLM {&lt;br /&gt;  SOFTWARE {&lt;br /&gt;    Microsoft {&lt;br /&gt;      Windows {&lt;br /&gt;        CurrentVersion {&lt;br /&gt;          Explorer {&lt;br /&gt;            'Browser Helper Objects' {&lt;br /&gt;              ForceRemove '{D2F7E1E3-C9DC-4349-B72C-D5A708D6DD77}' = s &lt;br /&gt;'HelloWorldBHO' {&lt;br /&gt;                val 'NoExplorer' = d '1'&lt;br /&gt;              }&lt;br /&gt;            }&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;改为&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;HKLM {&lt;br /&gt;  NoRemove SOFTWARE {&lt;br /&gt;    NoRemove Microsoft {&lt;br /&gt;      NoRemove Windows {&lt;br /&gt;        NoRemove CurrentVersion {&lt;br /&gt;          NoRemove Explorer {&lt;br /&gt;            NoRemove 'Browser Helper Objects' {&lt;br /&gt;              ForceRemove '{D2F7E1E3-C9DC-4349-B72C-D5A708D6DD77}' = s &lt;br /&gt;'HelloWorldBHO' {&lt;br /&gt;                val 'NoExplorer' = d '1'&lt;br /&gt;              }&lt;br /&gt;            }&lt;br /&gt;          }&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;public IDispEventImpl&lt;1, CHelloWorldBHO, &amp;DIID_DWebBrowserEvents2, &lt;br /&gt;&amp;LIBID_SHDocVw, 1, 0&gt;&lt;br /&gt;&lt;br /&gt;应该改为&lt;br /&gt;&lt;br /&gt;public IDispEventImpl&lt;1, CHelloWorldBHO, &amp;DIID_DWebBrowserEvents2, &lt;br /&gt;&amp;LIBID_SHDocVw, 1, 1&gt; &lt;br /&gt;&lt;br /&gt;If the page has no frames, the event is fired once after the page is ready, but before any script has run.这句话有误，浏览器在下载到BODY内嵌的script标签的时候就会执行脚本。 &lt;br /&gt;&lt;br /&gt;those that fire DownloadBegin will also fire a corresponding DocumentComplete 这里DocumentComplete 应该是DownloadComplete。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-116546526689059240?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/116546526689059240'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/116546526689059240'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2006/12/some-notes-on-ie7-programming-1.html' title='Some notes on IE7 Programming - 1'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-117057052388949650</id><published>2006-12-07T22:25:00.000-08:00</published><updated>2008-01-15T00:35:27.141-08:00</updated><title type='text'>Some notes on Visual Studio 2005 - 3</title><content type='html'>1.&lt;br /&gt;How to bypass the WinSxS for CRT/MFC/ATL DLLs&lt;br /&gt;&lt;br /&gt;从某牛人的blog看到的&lt;br /&gt;&lt;br /&gt;May 14, 2006How to bypass the WinSxS for CRT/MFC/ATL DLLs&lt;br /&gt;Starting with VC8, you have two options to distribute the DLL version of the CRT/MFC/ATL with your application:&lt;br /&gt;&lt;br /&gt;You can redistribute the DLLs with your application in the same directory and also put a valid manifest for these DLLs into this directory &lt;br /&gt;You can install the redist.exe and the DLL will be installed in the WinSxS folder (on XP and later) &lt;br /&gt;So, if you want to be independed from global DLLs, you might think that you can simply put the DLLs into your applications directory. But this is a false conclusion.&lt;br /&gt;If a DLL is installed in the WinSxS folder, the local DLLs will be ignored. This might be even true, if a newer DLL was installed (for example by security hotfixes). This is possible due to policy redirections of these SxS-DLLs.&lt;br /&gt;In most cases this also makes sense, because you always get the latest (hopefully compatible) version of the DLL.&lt;br /&gt;&lt;br /&gt;But there might be some situations in which you might have full control over which DLLs are loaded from where. Now, Andre Stille (an other VC++ MVP), found a very simple solution : just remove the “publicKeyToken” attribute from the manifests!&lt;br /&gt;So an application manifest looks like:&lt;br /&gt;&lt;br /&gt;Application.exe.manifest:&lt;br /&gt;&lt;br /&gt; ?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;br /&gt; assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"&gt;&lt;br /&gt;  dependency&gt;&lt;br /&gt;    dependentAssembly&gt;&lt;br /&gt;      assemblyIdentity type="win32" name="Microsoft.VC80.CRT" &lt;br /&gt; version="8.0.50727.42" processorArchitecture="x86" /&gt;&lt;br /&gt;    /dependentAssembly&gt;&lt;br /&gt;  /dependency&gt;&lt;br /&gt; /assembly&gt;You must also set the correct verion-number of the DLL! And remove the “publicKeyToken” attribute.&lt;br /&gt;The manifest the for DLL looks like:&lt;br /&gt;&lt;br /&gt;Microsoft.VC80.CRT.Manifest:&lt;br /&gt;&lt;br /&gt; ?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt;&lt;br /&gt; assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"&gt;&lt;br /&gt;    assemblyIdentity type="win32" name="Microsoft.VC80.CRT" &lt;br /&gt; version="8.0.50727.42" processorArchitecture="x86"&gt;/assemblyIdentity&gt;&lt;br /&gt;    file name="msvcr80.dll"&gt;/file&gt;&lt;br /&gt;    file name="msvcp80.dll"&gt;/file&gt;&lt;br /&gt;    file name="msvcm80.dll"&gt;/file&gt;&lt;br /&gt; /assembly&gt;Now the CRT DLLs in the WinSxS will be ignored and only the local DLLs will be loaded.&lt;br /&gt;&lt;br /&gt;Thanks again to Andre Stille!&lt;br /&gt;&lt;br /&gt;一个更牛的问题是如何在win2000等环境中使用XP的效果，这个MSDN板上的某大牛干过，据说手工扒了N多WindowsXP文件过去，再修改调用方式，不过没有透露细节，可叹可叹&lt;br /&gt;&lt;br /&gt;2.&lt;br /&gt;如果想简单一点也可以这样偷懒&lt;br /&gt;&lt;br /&gt;from http://www.cnblogs.com/wuhanhoutao/archive/2008/01/09/1031928.html&lt;br /&gt;&lt;br /&gt;解决"应用程序配置不正确，程序无法启动" &lt;br /&gt;  &lt;br /&gt;      在使用 VC++2005环境下生成的程序，放置到未安装VC环境的机器下后，有时候会出现程序无法执行的错误，其提示是：应用程序配置不正确，程序无法启动，重新安装应用程序可能解决问题。&lt;br /&gt;&lt;br /&gt;      实际上，重装是解决不了问题的，解决的一种方法是查看*exe.intermediate.manifest文件，比如文件的内容是：&lt;br /&gt;&lt;br /&gt;?xml version='1.0' encoding='UTF-8' standalone='yes'?&gt;&lt;br /&gt;assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'&gt;&lt;br /&gt; dependency&gt;&lt;br /&gt;    dependentAssembly&gt;&lt;br /&gt;      assemblyIdentity type='win32' name='Microsoft.VC80.CRT' version='8.0.50727.762' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' /&gt;&lt;br /&gt;    /dependentAssembly&gt;&lt;br /&gt; /dependency&gt;&lt;br /&gt; dependency&gt;&lt;br /&gt;    dependentAssembly&gt;&lt;br /&gt;      assemblyIdentity type='win32' name='Microsoft.VC80.MFC' version='8.0.50727.762' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' /&gt;&lt;br /&gt;    /dependentAssembly&gt;&lt;br /&gt; /dependency&gt;&lt;br /&gt; dependency&gt;&lt;br /&gt;    dependentAssembly&gt;&lt;br /&gt;      assemblyIdentity type='win32' name='Microsoft.VC80.DebugCRT' version='8.0.50727.762' processorArchitecture='x86' publicKeyToken='1fc8b3b9a1e18e3b' /&gt;&lt;br /&gt;    /dependentAssembly&gt;&lt;br /&gt; /dependency&gt;&lt;br /&gt;/assembly&gt;&lt;br /&gt;&lt;br /&gt;  需要注意这个文件中的3个关键词：Microsoft.VC80.CRT，Microsoft.VC80.MFC和Microsoft.VC80.DebugCRT。寻找到...."Program Files"Microsoft Visual Studio 8"VC"redist文件夹下面，找到这些名称的子文件夹，拷贝它们下面所有的文件到希望发布的EXE文件下面，一起打包。这些文件也就是mfc80.dll，msvcr80.dll，msvcp80.dll和Microsoft.VC80.CRT.manifest等。此错误发生的原因是在目标机器上需要这些文件的支持。&lt;br /&gt;&lt;br /&gt;（按：实际上我只用到了Microsoft.VC80.CRT，Microsoft.VC80.MFC这两个目录里面的文件，和自己的程序打包放在一个目录下面即可）&lt;br /&gt;&lt;br /&gt;3.&lt;br /&gt;Added 1/15/2008&lt;br /&gt;&lt;br /&gt;If you are confused by VS2005 which tells you cannot find some basic Afx functions, just add the following lines in your stdafx.h of your project&lt;br /&gt;&lt;br /&gt;#include "C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\src\mfc\afximpl.h"&lt;br /&gt;&lt;br /&gt;Then re-build, it could work&lt;br /&gt;&lt;br /&gt;Of course the directory above depends where you installed your VS2005&lt;br /&gt;&lt;br /&gt;Just my five cents&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-117057052388949650?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/117057052388949650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/117057052388949650'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2006/12/some-notes-on-visual-studio-2005-3.html' title='Some notes on Visual Studio 2005 - 3'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-116624299887877016</id><published>2006-12-06T20:18:00.000-08:00</published><updated>2008-01-15T00:26:54.009-08:00</updated><title type='text'>Some notes on Visual Studio 2005 -2</title><content type='html'>Actually, this post collects the notes about Visual Studio 2005 SP1&lt;br /&gt;&lt;br /&gt;1.&lt;br /&gt;发信人: hBifTs (OS真过瘾...), 信区: DotNET&lt;br /&gt;标  题: Re: vs2005sp1 out&lt;br /&gt;发信站: 水木社区 (Sat Dec 16 01:25:18 2006), 站内&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;安裝過程相當久 20~30分, 安裝過程中為避免重新安裝&lt;br /&gt;需注意底下兩點&lt;br /&gt;1)已安裝 beta sp1 須先行移除&lt;br /&gt;2)XP/2003作業下安裝, 需先做相關設定&lt;br /&gt;http://support.microsoft.com/kb/925336&lt;br /&gt;&lt;br /&gt;哈哈.我第一次也没注意....&lt;br /&gt;&lt;br /&gt;【 在 ICollection (集合) 的大作中提到: 】&lt;br /&gt;: 晕死，现在告诉我有一个文件没有通过数字签名验证，直接安装失败……&lt;br /&gt;&lt;br /&gt;http://support.microsoft.com/kb/925336&lt;br /&gt;&lt;br /&gt;SYMPTOMS&lt;br /&gt;When you try to install a large Microsoft Windows Installer (.msi) package or a large Microsoft Windows Installer patch (.msp) package on a computer that is running Microsoft Windows Server 2003 or Microsoft Windows XP, you receive the following error message:&lt;br /&gt;Error 1718. File FileName was rejected by digital signature policy.&lt;br /&gt;&lt;br /&gt;CAUSE&lt;br /&gt;This problem occurs when the computer has insufficient contiguous memory for Windows Server 2003 or Windows XP to verify that the .msi package or the .msp package is correctly signed.&lt;br /&gt;&lt;br /&gt;WORKAROUND&lt;br /&gt;To work around this problem, follow these steps:1. Click Start, click Run, type control admintools, and then click OK. &lt;br /&gt;2. Double-click Local Security Policy. &lt;br /&gt;3. Click Software Restriction Policies. &lt;br /&gt;&lt;br /&gt;Note If no software restrictions are listed, right-click Software Restriction Policies, and then click Create New Policy. &lt;br /&gt;4. Under Object Type, double-click Enforcement. &lt;br /&gt;5. Click All users except local administrators, and then click OK. &lt;br /&gt;6. Restart the computer. &lt;br /&gt;Important After you follow the previous steps, local administrators can install the .msi package or the .msp package. After the package is installed, reset the enforcement level by following the previous steps. In step 5, click All users instead of All users except local administrators.&lt;br /&gt;&lt;br /&gt;MORE INFORMATION&lt;br /&gt;Digital signatures help make sure that a package has not been tampered with. Windows Server 2003 and Windows XP use an additional level of security, Software Restriction Policies, when Windows Installer calls the SaferIdentifyLevel function. &lt;br /&gt;&lt;br /&gt;When Windows Installer calls the SaferIdentifyLevel function together with the SAFER_CRITERIA_IMAGEHASH flag, the whole package is loaded into memory on the computer. The computer must have sufficient contiguous memory for the package size. If the computer has insufficient contiguous memory, an error occurs. Because an error occurs, Windows Installer cannot verify that the package is correctly signed. Therefore, you receive the error message that is mentioned in the "Symptoms" section.&lt;br /&gt;&lt;br /&gt;The following log data shows the sequence of events when this problem occurs:MSI (s) (BA:AD) [12:00:00:000]: SOFTWARE RESTRICTION POLICY: Verifying object --&gt; 'D:\WINDOWS\Installer\50baad.msp' against software restriction policy&lt;br /&gt;MSI (s) (BA:AD) [12:00:00:000]: SOFTWARE RESTRICTION POLICY: D:\WINDOWS\Installer\50baad.msp has a digital signature&lt;br /&gt;MSI (s) (BA:AD) [12:00:00:000]: SOFTWARE RESTRICTION POLICY: SaferIdentifyLevel reported failure. Assuming untrusted. . . (GetLastError returned 5)&lt;br /&gt;MSI (s) (BA:AD) [12:00:00:000]: The installation of D:\WINDOWS\Installer\50baad.msp is not permitted due to an error in software restriction policy processing. The object cannot be trusted.&lt;br /&gt;&lt;br /&gt;2.&lt;br /&gt;From http://blog.joycode.com/scottgu/archive/2006/12/20/89372.aspx&lt;br /&gt;&lt;br /&gt;【原文地址】 HTML Source Editing Performance Improvements in VS 2005 SP1 &lt;br /&gt;【原文发表日期】 Tuesday, December 19, 2006 1:25 AM &lt;br /&gt;&lt;br /&gt;VS 2005 SP1上个星期在网上正式发布了。VS 2005 SP1的一个总的目标是改进许多常见的用例场景下的IDE的性能和响应性。这里是几个场景例子：Build时间，管理大型项目，重构和Intellisense。&lt;br /&gt;&lt;br /&gt;对于web场景，我们特别地对HTML源码编辑器的性能费了一番功夫，尤其是涉及大HTML文件或者比较慢的机器的情形。下面是在这个方面我们在SP1里做的几个改进性能的具体变动： &lt;br /&gt;&lt;br /&gt;1) 我们对HTML验证功能的性能做了调整，关于这功能的详情请见我以前的一篇老贴子。现在对大文件的验证非常快，并不会对文字键入或更新造成什么影响，而在以前，当你在HTML源码编辑模式下键入文字，而文件处于验证过程中时，验证有时会造成轻微的顿挫(stutter)。 &lt;br /&gt;&lt;br /&gt;2) 我们修正了一个使用场景的问题，这个使用场景是这样的，假如你关闭了HTML验证，然后编辑一个有HTML验证错误的网页，然后转换到即见即所得(WYSIWYG)设计模式，验证会自动启动，帮你识别错误所在。这虽然对调试错误非常有用，但很多人发现这个功能非常讨厌，因为这意味着，验证会在不为人所知的情形下不断地重新启动，在很慢的机器上或者文件很大的情形下，这对性能大有影响。而现在，当你关闭验证时，这验证就一直是关掉的。当你试着转换到WYSIWYG 设计模式时，如果有什么障碍的话，我们会为你识别错误所在，但我们不会为所有的东西重新启动验证。 &lt;br /&gt;&lt;br /&gt;3) 我们添加了一个选项，可以关闭HTML源码编辑模式中的属性网格( property grid )的使用。在我们的性能检测样品中，我们发现，当你在整个文件中移动光标时，把与当前光标所在元素相应的正确的HTML schema在属性网格中持续更新显示会占用不可小看的CPU时间。在与客户交流后，我们发现，大多数人其实并不使用这功能(注：在HTML源码模式中对服务器端控件的属性网格的支持是VS 2005中的一个新功能，VS 2003中是不存在的)。假如你不使用这功能，或者在一个很慢的机器上，那么我建议还是禁止这功能为好。 &lt;br /&gt;&lt;br /&gt;注意事项(如果你需要在HTML源码模式里启用属性网格支持的话)&lt;br /&gt;&lt;br /&gt;象我在上面提到的，在VS 2005 SP1中，我们现在可以配置在HTML源码模式里是否使用属性网格。因为我们交流过的大多数开发人员并不使用这个功能(实际上，大多数人都没有意识到这个功能的存在 )，我们决定，在SP1中这个功能的默认配置是禁止的。这意味着，当你在SP1中在HTML源码编辑模式中工作时，你将看到属性网格是象这个样子的：&lt;br /&gt;&lt;br /&gt;如果你要在源码模式里重新启用属性网格，这样，随着你在文件中移动光标，它就能被动态更新，只要打开工具-&gt;选项菜单项，然后在文字编辑器-&gt;HTML-&gt;杂类中，点击“在源码视图中启用属性网格(Enable Property Grid in Source View)”配置选项就可以了：&lt;br /&gt;&lt;br /&gt;这样你就重新启用了属性网格，就象是在VS 2005 RTM 里一样：&lt;br /&gt;&lt;br /&gt;请注意，这个设置对HTML即见即所得(WYSIWYG )设计模式中的属性网格或任何其他设计器不会有什么影响，属性网格在那些场景中总是被启用和显示的。它只对HTML源码编辑模式会有影响，这是个我们认为是非常罕见的使用场景。 &lt;br /&gt;&lt;br /&gt;希望本文对你有所帮助，&lt;br /&gt;&lt;br /&gt;Scott&lt;br /&gt;&lt;br /&gt;标签： ASP.NET, Visual Studio, .NET&lt;br /&gt;&lt;br /&gt;（按：转载这篇文章只是表示对Visual Studio源代码编辑器持续改进的支持，要知道曾经碰到VS2003的源代码编辑器居然因为打开cpp文件死锁，据说是正则表达式出错，委实Faint）&lt;br /&gt;&lt;br /&gt;3.&lt;br /&gt;From http://blog.joycode.com/scottgu/archive/2006/12/18/89292.aspx&lt;br /&gt;&lt;br /&gt;Visual Studio 2005 Service Pack 1 (SP1) 发布了&lt;br /&gt;&lt;br /&gt;【原文地址】 Visual Studio 2005 Service Pack 1 (SP1) Released &lt;br /&gt;【原文发表日期】 Friday, December 15, 2006 1:21 PM &lt;br /&gt;&lt;br /&gt;昨天Visual Studio推出了VS 2005 SP1的最终版。即刻就可以下载所有十个语言(英语，法语，西班牙语，意大利语，日语，朝鲜语，俄语，简单和繁体中文)的版本，你可以在这里下载和安装。 &lt;br /&gt;&lt;br /&gt;这个SP发布是个非常重大的服务包，融合了很多bug fixes和来自客户的反馈。该服务包中内置包括的还有对VS 2005 Web应用项目的支持(我们曾在5月份时为此提供过一个单独的下载)。它也包括了对整个产品的许多设计时性能优化和修正。 &lt;br /&gt;&lt;br /&gt;服务包安装的一些建议&lt;br /&gt;&lt;br /&gt;服务包本身是个非常大的下载，其大小为431M，取决于你已经安装的VS 的版本以及启用的功能，更新你的Visual Studio 2005 安装会花费30-90分钟。所以你应该预先计划好，别指望这个是几秒钟的操作(注：最好是在午饭前或晚上开始下载/安装)。 &lt;br /&gt;&lt;br /&gt;对安装过程的几个建议/评注：&lt;br /&gt;&lt;br /&gt;1) 在开始SP1更新前，假如你在你系统上安装了那个单独的VS 2005 Web应用项目的话，确认你将它卸载了。你不再需要它了，因为它的支持是内置于SP1中的，假如你安装了它的话，SP1安装程序会停止，让你将它卸载了才会继续下去。你现有的web应用项目文件还会继续工作，所以你对它们不需要做什么更新。&lt;br /&gt;&lt;br /&gt;2) SP1 会对它在你的系统上发现的每一份Visual Studio 2005运行升级/补丁的过程。所以，如果你在你的系统上安装了VS 2005 Professional，Visual Web Developer Express 和Visual Basic Express 的话，它就会运行这个补丁过程3次，因为每个安装对一些文件都有单独的拷贝。如果你并不使用你系统上的所有这些版本的话，你也许要卸载其中的一些版本，这样既省些硬盘空间，也可加速SP1安装过程。&lt;br /&gt;&lt;br /&gt;3) SP1会修补更新你安装的VS 2005 中的所有文件和功能。当我安装VS 2005时，有时我会点击“安装所有的东西”，这样的情形下，我会得到很多我不常用的功能，譬如，ATL，MFC等东西的 C++ 头文件和库文件源码。我在我个人系统上看到的情形是，当我只安装了我常用的功能的话，SP1升级过程从头到尾只花15分钟左右。但安装了所有东西的话，它会花上45-50分钟。假如你不用VS的某些功能，既想省些硬盘空间也想加速SP1安装过程的话，你也许要考虑不选VS的这些功能。&lt;br /&gt;&lt;br /&gt;最后一个关于build性能的建议&lt;br /&gt;&lt;br /&gt;SP1包括了build性能方面的许多改进，无论是VB 还是C#项目。想了解如何在VS 2005中优化网站和Web项目build性能方面的建议的话，我强烈建议你看一下我这里的优化build性能的博客贴子。这将会帮助你极大地优化你的build时间，对RTM和SP1系统都适用。&lt;br /&gt;&lt;br /&gt;希望本文对你有所帮助，&lt;br /&gt;&lt;br /&gt;Scott&lt;br /&gt;&lt;br /&gt;附注：有些人注意到了我网站上的图片和样例下载目前有问题。不幸的是，Puget Sound地区昨晚刚遭受了非常大的暴雨袭击，在凌晨一点前不久(正好是昨晚我完成ASP.NET AJAX RC贴子后的3分钟时，我点击提交按钮真及时啊 )，该地区所有的电源都中断了。我家和微软园区此刻都没有电，这意味着存有我图片和下载的主机目前不在运行。他们希望在几天内恢复电源，到时我的服务器(希望如此)就会上线了。在那之前，我会逗留在一个非常拥挤的Starbucks里取暖和借光，email也会时有时无。我对任何延迟预表歉意。&lt;br /&gt;&lt;br /&gt;标签： ASP.NET, Visual Studio, .NET&lt;br /&gt;&lt;br /&gt;4.&lt;br /&gt;From http://blog.joycode.com/ghj/archive/2006/12/21/89467.aspx&lt;br /&gt;&lt;br /&gt;昨天装Vista碰到的问题以及解决方案&lt;br /&gt;&lt;br /&gt;昨天花了一天时间装Vista，以及调整相关软件配置，中间碰到了一些问题，特整理如下：&lt;br /&gt;&lt;br /&gt;一、Vista 的序列号跟版本捆绑。而Vista 的光盘一般是各个版本的内容都包含，安装时候，根据你输入的序列号，自动给你装对应的版本。&lt;br /&gt;&lt;br /&gt;        我昨天装的是中文64位Vista，安转好后，显示的版本是：Windows Vista Business ，而不是Windows Vista Ultimate。原因就是因为我最开始输入序列号的时候，输成了Business 的序列号，而不是 Ultimate 的序列号。安装过程中，也就不会让我选择版本。&lt;br /&gt;&lt;br /&gt;        昨天由于不明白这个道理，而且没有注意到自己输入的序列号是 Business 的序列号，而不是 Ultimate 的序列号，安装后看到不是Windows Vista Ultimate，才引出后面的一系列问题。安装后，我又装了一些其他软件，比如虚拟光驱 DAEMON Tools 4.08HE (64 bit)。后来发现不是Ultimate，我在已经安装好Windows Vista Business 的基础上，再次用原盘升级安装，（这时候我仍然没有注意到我一直输入的是 Business  的序列号，仍然再次输入了 Business  序列号）希望升级到 Ultimate 版，花费了数个小时后，升级完毕，但是看我的电脑属性，仍然是 Business 版本。&lt;br /&gt;&lt;br /&gt;        但是升级后，我的虚拟光驱出问题了，开机就报虚拟光驱驱动错误。在安装的程序列表中，找不到DAEMON Tools ，就更谈不上这个程序的卸载了。&lt;br /&gt;&lt;br /&gt;        安装过程中，Vista 已经提示我 DAEMON Tools  用的存储控制器 SCSI/ RAID Host Controller 有问题。但是仍然可以继续安装，安装完成后，就出现了下面的问题。&lt;br /&gt;&lt;br /&gt;二、特殊情况下，Vista 下虚拟光驱软件的卸载问题。&lt;br /&gt;&lt;br /&gt;       当时我直接执行DAEMON Tools 安装目录下的卸载程序卸载，也不能卸载。（正常是应该可以卸载的）。后来我修改了注册表，删除了已知虚拟光驱的目录，这时候，程序启动不报错了。但是我无法重新安装虚拟光驱。每次安装到一半，都会报"You must reboot after previous operation."'，选择yes，重起电脑，每次都这样。陷入了一个死循环。最后使用了提供该虚拟光驱软件网站提供的另外一个工具： SPTDinst-v138-x64  ，才彻底把有问题的驱动卸载掉。同时也可以重新安装虚拟光驱。&lt;br /&gt;&lt;br /&gt;三、中文Vista + 中文Office 2007 + 英文 VS2005 的结果是，VS2005 菜单中，中英文混杂。&lt;br /&gt;&lt;br /&gt;        我的XP的笔记本是 中文 XP + 中文 Office 2007 + 英文 VS2005 ，我的 VS2005 就不存在菜单中，中英文混杂的问题。&lt;br /&gt;&lt;br /&gt;四、在针对Vista的 VS2005 SP1 出来前，VS2005 每次打开应该选择以管理员身份运行。&lt;br /&gt;&lt;br /&gt;        否则你会看到各种错误，但是原因都是因为没有权限干某某事情。 VS2005 的普通 SP1 也是这个问题。&lt;br /&gt;&lt;br /&gt;五、比较奇怪的是，默认情况下，在控制面板--&gt; 管理工具中， 你默认看不到“组件服务”这项，你如果需要使用和配置组件服务，需要自己先运行 mmc ，然后添加\删除管理单元。&lt;br /&gt;&lt;br /&gt;        不知道是不是我这个版本的Vista 的问题。难道有 WCF 了，微软希望“组件服务”将被人们所遗忘？？&lt;br /&gt;&lt;br /&gt;# 回复: 昨天装Vista碰到的问题以及解决方案 &lt;br /&gt;2006-12-21 9:06 by 开心就好 &lt;br /&gt;感觉像回到了论坛时代。 &lt;br /&gt;1. 关于你的Vista版本问题。问题的关键取决于你的序列号，你的序列号中已经有一个信息标记你当前可以安装的版本是什么了。所以在输入序列号的界面时，可以先忽略直接到下一步，你就可以选择版本了，比如Ultimate。但切记要在激活期结束前取得Ultimate的激活序列号。 &lt;br /&gt;&lt;br /&gt;2. 这个问题与下面问题我无法明白，难道与Vista的版本有任何关联？“就是因为看到安装后不是Windows Vista Ultimate，才引出后面的一系列问题。”？Vista所有版本都基于同一Code base，所以这与某某无关的。 另外，在你升级前，你确保DAEMON Tools可以使用吗？实在没有办法的情况下，你可以Windows Intaller Cleaner的一个小软件。 &lt;br /&gt;&lt;br /&gt;3. 我的是英文Vista（中文语言包）+中文Office 2007+中文VS 2005，所以不存在中英文混杂的情况。切记，查看一下你的VS 2005中的当前语言选项是使用的默认操作系统语言还是VS 2005的语言。 &lt;br /&gt;&lt;br /&gt;4. VS 2005 SP1已经出来了，它本身不包括一个Vista update for VS 2005的组件。不过马上就会发布此组件了。别着急：），VS 2005可以先设置为Run as administrator，思归翻译的ScottGu的文章中有介绍。另外，你可以先禁掉UAC也可以（不建议）。 &lt;br /&gt;&lt;br /&gt;5. 可能是根据调查数据显示，组件服务并不是大多数人优先使用的工具，所以把它的优先级给调低了。 &lt;br /&gt;&lt;br /&gt;这几个问题总结得还是不够深度呀。 :) 有一种论坛神医的感觉。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-116624299887877016?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/116624299887877016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/116624299887877016'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2006/12/some-notes-on-visual-studio-2005-2.html' title='Some notes on Visual Studio 2005 -2'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-116105365682618540</id><published>2006-12-05T19:50:00.000-08:00</published><updated>2006-12-21T22:36:27.170-08:00</updated><title type='text'>Some notes on Visual Studio 2005 -1</title><content type='html'>正在Porting原来的项目到Visual Studio 2005，遇到了很多奇怪的Bug，这里记载一些&lt;br /&gt;&lt;br /&gt;1.&lt;br /&gt;From http://blog.dragon2.net/archives/2006/03/08/300.php&lt;br /&gt;&lt;br /&gt;Compiler Warning C4819 (C++)&lt;br /&gt;&lt;br /&gt;用了 Microsoft Visual Studio 2005 之後本來還覺得不錯，沒想到這幾天為了要安裝 Boost library，終於出問題了。&lt;br /&gt;&lt;br /&gt; 首先照著說明文件打指令，bjam 要先安裝就是了。當然這些都不是什麼大問題，不過裝著裝著問題就來了，怎麼會有一堆 warning C4819 咧？本來是不以為意啦（誰會想要去理 warning 啊），不過美好的一切就在 Visual Studio 2005 告訴你找不到 regex library 時破滅了！！！&lt;br /&gt;&lt;br /&gt;追根究底，這樣出現 C4819 warning 的檔案，如果直接去開，那麼會發現裡面有亂碼。亂碼問題不大，問題是有些會影響到 compiler 的判斷。也就是原來放在註解的某些字元一下子就變成 code 了，所以 boost 在安裝的時候就少了幾個 library 沒放上去，也造成了 regex 沒法用（其實我只要用 regex 而已，其他的我不清楚）！&lt;br /&gt;&lt;br /&gt; 因為字碼（codepage）都亂了，本來用 vim/notepad 開啟後另存為 Unicode 模式也沒用（因為打開時就爛了）。現在有想到一個白痴的方法，就是找台 FreeBSD 機器，用它來幫我轉換（用 vi/vim 開檔雖然也有亂碼，不過按 ga 時 hex 值還是對的）。正在試….&lt;br /&gt;&lt;br /&gt;Updated: 上面的方法還是不行，現在用鋸箭法解決了，把有問題的 / ? / 砍掉，反正註解我也看不到，也不用懂了。&lt;br /&gt;&lt;br /&gt;Reference &lt;br /&gt;The new compiler error C4819&lt;br /&gt;http://blogs.msdn.com/michkap/archive/2005/01/05/347394.aspx&lt;br /&gt;&lt;br /&gt;More on the C4819 error &lt;br /&gt;http://blogs.msdn.com/michkap/archive/2005/12/09/502290.aspx&lt;br /&gt;&lt;br /&gt;Compiler Warning (level 1) C4819 (C++) &lt;br /&gt;http://msdn2.microsoft.com/en-us/library(d=robot)/ms173715.aspx&lt;br /&gt;&lt;br /&gt;luoge Says: &lt;br /&gt;十月 3rd, 2006 at 12:25 pm &lt;br /&gt;I just found there is a software “FAR”, which can convert ansi files to unicode files. I have compiled the library with vc++ 2005 successfully after doing the conversion.&lt;br /&gt;&lt;br /&gt;http://www.helpware.net/FAR/help/Unicode.htm&lt;br /&gt;&lt;br /&gt;2.&lt;br /&gt;From http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=220821&amp;SiteID=1&lt;br /&gt;&lt;br /&gt;Rob Caldecott  25 Jan 2006, 11:46 PM UTC  &lt;br /&gt; &lt;br /&gt;I have found a serious problem with the Visual Studio 2005 Professional resource editor.  I am based in the UK (this is crucial), and when I add a new resource to an MFC project, it is assigned the English (United Kingdom) language by default.  Unfortunately, the following line is added to the .rc file, which will not compile:&lt;br /&gt;&lt;br /&gt;LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_NEUTRAL&lt;br /&gt;&lt;br /&gt;The resource compiler will produce the following:&lt;br /&gt;&lt;br /&gt;error RC2147 : SUBLANGUAGE ID not a number&lt;br /&gt;&lt;br /&gt;It *should* be using SUBLANG_ENGLISH_UK instead.&lt;br /&gt;&lt;br /&gt;If I add a new resource and then attempt to change the language to English (US), then it fails and the error persists.  This means that every time I add a new resource, I am forced to edit the .rc file by hand in order for it to compile, which is very time-consuming and prone to error.&lt;br /&gt;&lt;br /&gt;Does anyone have a workaround for this?  I guess I could define &lt;br /&gt;SUBLANG_ENGLISH_NEUTRAL as SUBLANG_ENGLISH_UK somewhere.  Note also that  SUBLANG_ENGLISH_NEUTRAL is nowhere to be found in the Visual C++ headers.&lt;br /&gt;&lt;br /&gt;Ted. 26 Jan 2006, 12:25 AM UTC  &lt;br /&gt;  &lt;br /&gt;There's already a bug for this &lt;br /&gt;&lt;br /&gt;http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx?feedbackid=3b49aa31-fa2b-419e-927a-0b16ccc0e18b&lt;br /&gt;&lt;br /&gt;the people at Microsoft claim it's not reproduceable in builds after Beta 2.  Which build are you running? &lt;br /&gt;&lt;br /&gt;Rob Caldecott 26 Jan 2006, 8:19 AM UTC  &lt;br /&gt; &lt;br /&gt;I am running the official build:&lt;br /&gt;8.0.50727.42 (RTM.050727-4200)&lt;br /&gt;&lt;br /&gt;Ted. 26 Jan 2006, 1:27 PM UTC  &lt;br /&gt;&lt;br /&gt;The bug has now been reopened (see above link) - please feel free to add any more information you have to it.&lt;br /&gt;&lt;br /&gt;3.&lt;br /&gt;发信人: cygwin (空), 信区: MSDN&lt;br /&gt;标  题: 这时我理解错误还是vc Bug?&lt;br /&gt;发信站: 水木社区 (Sat Nov  4 14:08:44 2006), 站内&lt;br /&gt;&lt;br /&gt;#include &lt;iostream&gt;&lt;br /&gt;#include &lt;locale&gt;&lt;br /&gt;&lt;br /&gt;int main(int argc, char* argv[])&lt;br /&gt;{&lt;br /&gt;        setlocale(LC_ALL, "chs");&lt;br /&gt;        wprintf(L"测试1\n");&lt;br /&gt;&lt;br /&gt;        std::locale loc("chs");&lt;br /&gt;        std::wcout.imbue(loc);&lt;br /&gt;        std::wcout &lt;&lt; L"测试2" &lt;&lt; std::endl;&lt;br /&gt;&lt;br /&gt;        return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;main函数体中前两行，使wprintf能输出中文，&lt;br /&gt;后三行使wcout输出中文，这两个单独执行时都是好的，&lt;br /&gt;&lt;br /&gt;但是现在放在一起，后面的那个“测试2”出不来，&lt;br /&gt;是我傻了还是vc傻了啊？&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;编译器为vs2005&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;&lt;br /&gt;※ 修改:·cygwin 于 Nov  4 14:09:17 修改本文·[FROM: 219.134.113.*]&lt;br /&gt;※ 来源:·水木社区 http://newsmth.net·[FROM: 219.134.113.*]&lt;br /&gt;&lt;br /&gt;发信人: Quaful (夸父|要找工作咯), 信区: MSDN&lt;br /&gt;标  题: Re: 这时我理解错误还是vc Bug?&lt;br /&gt;发信站: 水木社区 (Sat Nov  4 16:07:47 2006), 站内&lt;br /&gt;&lt;br /&gt;呵呵，通常我们写程序的时候，都有一条注意事项，就是 setlocale 和 std::locale 不能混用。至于为什么的话以前我没有细究过，今天你提了这个问题，本来我想就此琢磨一下到底是什么地方引起了两者的不兼容，不过翻了半天 CRT 和 iostream 的代码，有点乱，呵呵。简单的想，可能是这样一个原因：wprintf 并不是一个 unicode 的输出函数，它实际上是根据 setlocale 设置的 locale 信息把参数里面的 wchar_t 转换为对应的 MBCS；wcout 也是一样。如果混用了 setlocale 和 std::locale，转换的过程中可能就会出问题。&lt;br /&gt;&lt;br /&gt;【 在 cygwin (空) 的大作中提到: 】&lt;br /&gt;: #include &lt;iostream&gt;&lt;br /&gt;: #include &lt;locale&gt;&lt;br /&gt;: int main(int argc, char* argv[])&lt;br /&gt;: ...................&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;&lt;br /&gt;※ 来源:·水木社区 newsmth.net·[FROM: 221.219.7.*]&lt;br /&gt;&lt;br /&gt;发信人: fireseed (昏睡), 信区: MSDN&lt;br /&gt;标  题: Re: 这时我理解错误还是vc Bug?&lt;br /&gt;发信站: 水木社区 (Sat Nov  4 23:48:07 2006), 站内&lt;br /&gt;&lt;br /&gt;中间加一句：&lt;br /&gt;                setlocale(LC_ALL, "C");&lt;br /&gt;就可以了&lt;br /&gt;&lt;br /&gt;【 在 cygwin (空) 的大作中提到: 】&lt;br /&gt;: #include &lt;iostream&gt;&lt;br /&gt;: #include &lt;locale&gt;&lt;br /&gt;: int main(int argc, char* argv[])&lt;br /&gt;: ...................&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;&lt;br /&gt;※ 来源:·水木社区 newsmth.net·[FROM: 222.240.210.*]&lt;br /&gt;&lt;br /&gt;发信人: Quaful (夸父|毕业毕业), 信区: MSDN&lt;br /&gt;标  题: VS2005中fstream不支持中文文件名的BUG的原因及简单workaround&lt;br /&gt;发信站: 水木社区 (Mon Dec  4 10:31:13 2006), 站内&lt;br /&gt;&lt;br /&gt;VS2005里面的fstream在打开文件的时候，如果传入的文件名中有中文字符，则打开常常会失败。查代码，原来是因为fstream打开文件调用的是Fiopen函数：&lt;br /&gt;（VC\crt\src\fiopen.cpp, line 9）&lt;br /&gt;_MRTIMP2_NCEEPURE FILE *__CLRCALL_PURE_OR_CDECL _Fiopen(const char *filename,&lt;br /&gt;        ios_base::openmode mode, int prot)&lt;br /&gt;{       // open wide-named file with byte name&lt;br /&gt;        wchar_t wc_name[FILENAME_MAX];&lt;br /&gt;&lt;br /&gt;        // 在这里出错&lt;br /&gt;        if (mbstowcs_s(NULL, wc_name, FILENAME_MAX, filename, FILENAME_MAX - 1) != 0)&lt;br /&gt;                return (0);&lt;br /&gt;        return _Fiopen(wc_name, mode, prot);&lt;br /&gt;}&lt;br /&gt;那么就可以知道是locale的原因了，简单的workaround就是调用一个setlocale&lt;br /&gt;例：&lt;br /&gt;setlocale(LC_ALL, "chs");&lt;br /&gt;std::ifstream test("你好.txt");&lt;br /&gt;if(file)&lt;br /&gt;{&lt;br /&gt;        // do sth.&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;&lt;br /&gt;※ 来源:·水木社区 newsmth.net·[FROM: 124.42.96.*]&lt;br /&gt;&lt;br /&gt;发信人: flybb (zz), 信区: MSDN&lt;br /&gt;标  题: Re: VS2005中fstream不支持中文文件名的BUG的原因及简单workaro&lt;br /&gt;发信站: 水木社区 (Mon Dec  4 10:41:53 2006), 站内&lt;br /&gt;&lt;br /&gt;然后cout就不能输出中文了&lt;br /&gt;&lt;br /&gt;【 在 Quaful (夸父|毕业毕业) 的大作中提到: 】&lt;br /&gt;: VS2005里面的fstream在打开文件的时候，如果传入的文件名中有中文字符，则打开常常会失败。查代码，原来是因为fstream打开文件调用的是Fiopen函数：&lt;br /&gt;: （VC\crt\src\fiopen.cpp, line 9）&lt;br /&gt;: _MRTIMP2_NCEEPURE FILE *__CLRCALL_PURE_OR_CDECL _Fiopen(const char *filename,&lt;br /&gt;: ...................&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;&lt;br /&gt;※ 来源:·水木社区 newsmth.net·[FROM: 218.104.71.*]&lt;br /&gt;&lt;br /&gt;发信人: Quaful (夸父|毕业毕业), 信区: MSDN&lt;br /&gt;标  题: Re: VS2005中fstream不支持中文文件名的BUG的原因及简单workaround&lt;br /&gt;发信站: 水木社区 (Mon Dec  4 10:56:06 2006), 站内&lt;br /&gt;&lt;br /&gt;就像前段时间讨论过的，还得用&lt;br /&gt;setlocale(LC_ALL, "C");&lt;br /&gt;改回来&lt;br /&gt;&lt;br /&gt;vs2005的stl确实很bt啊&lt;br /&gt;&lt;br /&gt;【 在 flybb (zz) 的大作中提到: 】&lt;br /&gt;: 然后cout就不能输出中文了&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;--&lt;br /&gt;&lt;br /&gt;※ 来源:·水木社区 newsmth.net·[FROM: 124.42.96.*]&lt;br /&gt;&lt;br /&gt;4.&lt;br /&gt;http://blog.joycode.com/jiangsheng/archive/2006/12/19/89320.aspx&lt;br /&gt;&lt;br /&gt;VC++ 2003 Managed Extensions to VC++2005 C++/CLI Conversion Tool，Visual C++的方向 &lt;br /&gt;Stan Lippman在C++/CLI Migration Primer中提到的mscfront已经以VC++ 2003 Managed Extensions to VC++2005 C++/CLI Conversion Tool的名字发布，下载地址在http://www.microsoft.com/downloads/details.aspx?FamilyID=a3581805-1af2-4c34-9d0e-6029cc078441&amp;displaylang=en。这个工具看起来并不完善，但是好在有源代码，可以自行修改来适应个人的代码。&lt;br /&gt;&lt;br /&gt;另外，在MSDN论坛的一个帖子中提到，Visual C++产品组在对产品的评估中决定将工作的重点转移回非托管代码。Visual C++产品组会加强对Windows非托管API的支持，以及提供托管和非托管代码的互操作性，但是在Orcas不会提供对所有.Net新特性的支持，例如LINQ和WPF。Orcas中确定的新特性只有STL/CLR（以前叫STL.Net)和对C++标准的进一步支持。虽然Windows Vista上有Desktop Window Manager API，但是在Windows XP上要用WPF的话还是得和其他语言的代码互操作。&lt;br /&gt;&lt;br /&gt;看起来Visual C++产品组还是没有解决支持partial class的问题，C++的编译模式使得在类编译成obj之后动态扩展比较困难。C++程序员只能继续在创建Form之后手动把设计器生成的函数实现搬到cpp文件里面去。&lt;br /&gt;&lt;br /&gt;（按：C++ is still alive）&lt;br /&gt;&lt;br /&gt;5.&lt;br /&gt;Upgrade Issue: Compile error C2327 with import dll under VC8/VS2005&lt;br /&gt;&lt;br /&gt;http://blog.csdn.net/carolbaby/archive/2006/12/22/1452489.aspx&lt;br /&gt;&lt;br /&gt;Issue:&lt;br /&gt;When I upgrade an exe project from VC7.1 to VC8, it says upgrade &lt;br /&gt;succeed. But When I try to compile the project, it outputs a lot of errors. &lt;br /&gt; &lt;br /&gt;..\debug\msado15.tlh(1024) : error C2327: 'CDO::_ADO::Properties' : is not a type name, static, or enumerator &lt;br /&gt;..\debug\msado15.tlh(2086) : error C2327: 'CDO::Command15::Parameters' : is not a type name, static, or enumerator &lt;br /&gt;..\debug\msado15.tlh(2285) : error C2327: 'CDO::Connection15::Errors' : is not a type name, static, or enumerator &lt;br /&gt;..\debug\msado15.tlh(2525) : error C2327: 'CDO::Recordset15::Fields' : is not a type name, static, or enumerator &lt;br /&gt;..\debug\msado15.tlh(3124) : error C2327: 'CDO::_Record::Fields' : is not a type name, static, or enumerator &lt;br /&gt;..\debug\msado15.tli(109) : error C2065: '_result' : undeclared identifier &lt;br /&gt;..\debug\cdosys.tlh(628) : error C2327: 'CDO::IConfiguration::Fields' : is not a type name, static, or enumerator &lt;br /&gt;..\debug\cdosys.tlh(814) : error C2327: 'CDO::IBodyPart::Fields' : is not a type name, static, or enumerator &lt;br /&gt;..\debug\cdosys.tlh(1090) : error C2327: 'CDO::IMessage::Fields' : is not a type name, static, or enumerator &lt;br /&gt;..\debug\cdosys.tlh(1100) : error C2327: 'CDO::IMessage::Fields' : is not a type name, static, or enumerator &lt;br /&gt; &lt;br /&gt;In my project, the import sentences are written like follows: &lt;br /&gt; &lt;br /&gt;#include "stdafx.h" &lt;br /&gt;#include "Resource.h" &lt;br /&gt;#include "ProcessorThread.h" &lt;br /&gt;#include &lt;string&gt; &lt;br /&gt;#import "c:\program files\common files\system\ado\msado15.dll" &lt;br /&gt;rename("ADODB","CDO") rename( "EOF", "adoEOF" ) &lt;br /&gt;#import &lt;cdosys.dll&gt; &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;Root Reason:&lt;br /&gt;The msado15.tlh and cdosys.tlh are not generated correctly. When I compare the .tlh file generated by 2003 and 2005, I noticed the keyword “struct” is missed in some method definitions in the tlh file generated by 2005.&lt;br /&gt;For example: in msado15.tlh&lt;br /&gt;virtual HRESULT __stdcall get_Item (&lt;br /&gt;        /*[in]*/ VARIANT Index,&lt;br /&gt;        /*[out,retval]*/ struct Property * * ppvObject ) = 0; // this struct is missed in the tlh generated under VS2005&lt;br /&gt; &lt;br /&gt;virtual HRESULT __stdcall get_Item (&lt;br /&gt;        /*[in]*/ VARIANT Index,&lt;br /&gt;        /*[out,retval]*/ struct Error * * ppvObject ) = 0;  // this struct is missed in the tlh generated under VS2005&lt;br /&gt; &lt;br /&gt;            &lt;br /&gt;The generation of tlh files is affected by some codes in this project, which is compiled earlier than the import sentences.&lt;br /&gt; &lt;br /&gt;Solution:&lt;br /&gt;Move the import sentences to the very beginning of stdafx.h. Maybe move to other positions could also make things work. The only thing I did is to make the import sentences compiled earlier than other sentences, by moving their position.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-116105365682618540?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/116105365682618540'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/116105365682618540'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2006/12/some-notes-on-visual-studio-2005-1.html' title='Some notes on Visual Studio 2005 -1'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-115900342936305205</id><published>2006-09-01T02:23:00.000-07:00</published><updated>2006-09-23T02:23:49.816-07:00</updated><title type='text'>侠客行</title><content type='html'>从那盘古开天劈地&lt;br /&gt;侠行天下是礼是义&lt;br /&gt;不战而胜最是理想&lt;br /&gt;人在江湖身不由己&lt;br /&gt;除暴安良一身正气&lt;br /&gt;闯荡江湖无人能敌&lt;br /&gt;哪怕不知去向何方&lt;br /&gt;努力下去就是希望&lt;br /&gt;这世界真的也许有太多的你不如意&lt;br /&gt;可你的生活虽然坎坎坷坷仍在继续&lt;br /&gt;希望就住在你的心底&lt;br /&gt;愿你勤勤恳恳善待别人关心自己&lt;br /&gt;美好的日子等你&lt;br /&gt;呛呛cei &lt;br /&gt;呛呛cei &lt;br /&gt;拿出勇气让我看&lt;br /&gt;呛呛cei &lt;br /&gt;呛呛cei &lt;br /&gt;要向上看不向下看&lt;br /&gt;呛呛cei &lt;br /&gt;呛呛cei &lt;br /&gt;要向前看不向后看&lt;br /&gt;呛呛cei &lt;br /&gt;呛呛cei &lt;br /&gt;要向好看不向坏看&lt;br /&gt;这世界有太多不如意&lt;br /&gt;但你的生活还是要继续&lt;br /&gt;太阳每天依旧要升起&lt;br /&gt;希望永远种在你心里&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-115900342936305205?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/115900342936305205'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/115900342936305205'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2006/09/blog-post.html' title='侠客行'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-114737509621638657</id><published>2006-06-30T12:14:00.000-07:00</published><updated>2006-05-11T12:20:06.263-07:00</updated><title type='text'>Some useful DotNet tools</title><content type='html'>1.&lt;br /&gt;http://www.jetbrains.com/products.html&lt;br /&gt;&lt;br /&gt;公司推出的&lt;br /&gt;&lt;br /&gt;Resharper http://www.jetbrains.com/resharper/&lt;br /&gt;The Simple And Super Fast Profiler For .NET http://www.jetbrains.com/profiler/&lt;br /&gt;&lt;br /&gt;2.&lt;br /&gt;http://www.aisto.com/roeder/dotnet/&lt;br /&gt;&lt;br /&gt;尤其是 Reflector for .NET&lt;br /&gt;&lt;br /&gt;3.&lt;br /&gt;n个VB.Net C#代码转换工具&lt;br /&gt;from http://www.cnblogs.com/blaze/archive/2004/10/22/55426.html&lt;br /&gt;&lt;br /&gt;1.http://www.kamalpatel.net/(最常用的,不过对于16进制的Int不能正常转换)&lt;br /&gt;在线版:VB.Net =&gt; C#   C#=&gt;VB.Net &lt;br /&gt;离线版:C#=&gt;VB.Net &lt;br /&gt;2.http://csharpconverter.claritycon.com/(推荐!非常好用的一个，几乎没出过太大的问题。)&lt;br /&gt;在线版:C#=&gt;VB.Net&lt;br /&gt;离线版:C#=&gt;VB.Net &lt;br /&gt;3.http://www.ragingsmurf.com/&lt;br /&gt;在线版:C#=&gt;VB.Net&lt;br /&gt;4.http://aspalliance.com/&lt;br /&gt;在线版:C#=&gt;VB.Net&lt;br /&gt;5.http://developerfusion.com/&lt;br /&gt;在线版:VB.Net =&gt; C#   C#=&gt;VB.Net&lt;br /&gt;大家如果有其它的欢迎评论告诉我一声&lt;br /&gt;最后送一个最管用的：呵呵，看了就知道.&lt;br /&gt;http://www.4guysfromrolla.com/webtech/012702-1.shtml&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-114737509621638657?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/114737509621638657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/114737509621638657'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2006/06/some-useful-dotnet-tools.html' title='Some useful DotNet tools'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-5145610219380705022</id><published>2006-06-15T02:47:00.000-07:00</published><updated>2008-01-15T03:08:54.502-08:00</updated><title type='text'>Some notes on SharpDevelop - 2</title><content type='html'>1.&lt;br /&gt;from http://www.cnblogs.com/michael-zhang/articles/621148.html&lt;br /&gt;http://www.cnblogs.com/michael-zhang/articles/629724.html&lt;br /&gt;http://www.cnblogs.com/michael-zhang/articles/636381.html&lt;br /&gt;http://www.cnblogs.com/michael-zhang/articles/651825.html&lt;br /&gt;http://www.cnblogs.com/michael-zhang/articles/655267.html&lt;br /&gt;&lt;br /&gt;SharpDevelop浅析_1_AddInTree&lt;br /&gt;&lt;br /&gt;使用ICSharpCode.Core创建插件支持的应用程序&lt;br /&gt;&lt;br /&gt;2、使用AddIn好处&lt;br /&gt;方便扩展，可以看到SharpDevelop几乎是通过插接功能模块组装而成；核心可以不必实现自己的定义，方便地通过接口扩充功能；插件dll可以放在任意位置，对插件使用拷贝、粘贴式的部署。&lt;br /&gt;许多应用程序也使用了一些插件机制，但大多数局限于特定的功能，如扩展菜单或新文件格式。SharpDevelop插件体系的目标是为应用程序提供简单易用而又强大的扩展点,allowing AddIns to extend nearly everything.&lt;br /&gt;&lt;br /&gt;3、AddIn实现分析：&lt;br /&gt;简单分析后，实现思路是这样的：定义一个接口ICommand，声明void DoCommand()方法，新增插件必须实现此接口；&lt;br /&gt;单击菜单项或工具栏按钮时需要与主窗体交互，这可以通过在ICommand中定义属性MainForm或在void DoCommand(MainForm frm)中增加方法参数来传递主窗体的引用，这些实现起来倒也简单。&lt;br /&gt;接下来的问题是如何通知应用程序新增加了插件呢，答案是使用xml配置文件，怎么组织这个配置文件的结构呢？这个问题其实成了实现插件功能的重点和难点，配置文件中希望说明新增插件的dll位置、类名、插接入主程序的菜单还是工具栏项、插接位置，或许还希望配置文件更容易被扩展？&lt;br /&gt;这里(http: //www.codeproject.com/cs/library/Net_AddinProjFrmwork.asp)有一个结构不太好的配置文件定义形式（可能也是我们简单分析后会想到的定义方式，可以看出结构固定，且不易扩展），大家可以自行分析下：&lt;br /&gt;sample.xml&lt;br /&gt; 1&lt;ProjectFrameworkAddin&gt;&lt;br /&gt; 2 &lt;AppVer&gt;1&lt;/AppVer&gt;&lt;br /&gt; 3 &lt;AddinName&gt;Report Addin&lt;/AddinName&gt;&lt;br /&gt; 4 &lt;ToobarButtonCount&gt;1&lt;/ToobarButtonCount&gt;&lt;br /&gt; 5 &lt;MainMenu&gt;&lt;br /&gt; 6  &lt;Name&gt;Bar Code&lt;/Name&gt;&lt;br /&gt; 7  &lt;ShortcutKeyIndex&gt;1&lt;/ShortcutKeyIndex&gt;&lt;br /&gt; 8  &lt;SubMenu&gt;&lt;br /&gt; 9      &lt;Name&gt;Bar Code&lt;/Name&gt;&lt;br /&gt;10      &lt;ShortcutKeyIndex&gt;1&lt;/ShortcutKeyIndex&gt;&lt;br /&gt;11    &lt;LeafMenu&gt;&lt;br /&gt;12      &lt;Name&gt;Test Menu&lt;/Name&gt;&lt;br /&gt;13      &lt;FunctionName&gt;AddinFunctionName&lt;/FunctionName&gt;&lt;br /&gt;14      &lt;HelpString&gt;Some Status bar text&lt;/HelpString&gt;&lt;br /&gt;15      &lt;ToolTip&gt;Some tool tip text&lt;/ToolTip&gt;&lt;br /&gt;16      &lt;ToolBarIndex&gt;Addin2Settings.ico&lt;/ToolBarIndex&gt;&lt;br /&gt;17      &lt;ShortCutKey&gt;Ctrl + H&lt;/ShortCutKey&gt;&lt;br /&gt;18    &lt;/LeafMenu&gt;&lt;br /&gt;19    &lt;LeafMenu&gt;&lt;br /&gt;20      ..&lt;br /&gt;21      ..&lt;br /&gt;22    &lt;/LeafMenu&gt; &lt;br /&gt;23  &lt;/SubMenu&gt;&lt;br /&gt;24  &lt;SubMenu&gt;&lt;br /&gt;25    ..&lt;br /&gt;26    ..&lt;br /&gt;27  &lt;/SubMenu&gt;&lt;br /&gt;28 &lt;/MainMenu&gt;&lt;br /&gt;29 &lt;MainMenu&gt;&lt;br /&gt;30  &lt;br /&gt;31  &lt;br /&gt;32 &lt;/MainMenu&gt;&lt;br /&gt;33&lt;/ProjectFrameworkAddin&gt;&lt;br /&gt;现在来看看SharpDevelop的AddIn配置文件结构（参见Demo中的Entry.myAddins.Menus.addin）： &lt;br /&gt;Menus.addin&lt;br /&gt; 1&lt;AddIn name        = "basic menus"&lt;br /&gt; 2       author      = "michael zhang"&lt;br /&gt; 3       url         = "http://www.cnblogs.com/michael-zhang/"&lt;br /&gt; 4       description  = "基本插件"&lt;br /&gt; 5       addInManagerHidden = "true"&gt;&lt;br /&gt; 6  &lt;Manifest&gt;&lt;br /&gt; 7    &lt;Identity name="michael.addin.basic" version = "@EntryAssemblyVersion"/&gt;&lt;br /&gt; 8  &lt;/Manifest&gt;&lt;br /&gt; 9  &lt;Runtime&gt;&lt;br /&gt;10    &lt;Import assembly = "..\MainForm.dll"/&gt;&lt;br /&gt;11  &lt;/Runtime&gt;&lt;br /&gt;12  &lt;Path name = "/michael/BlackText"&gt;&lt;br /&gt;13    &lt;FileFilter id = "Text" name = "Text files" extensions = "*.txt"/&gt;&lt;br /&gt;14    &lt;br /&gt;15  &lt;/Path&gt;&lt;br /&gt;16  &lt;Path name = "/michael/dymanic_Menus"&gt;&lt;br /&gt;17  &lt;/Path&gt;&lt;br /&gt;18  &lt;Path name = "/michael/myMenus"&gt;&lt;br /&gt;19    &lt;MenuItem id = "File"&lt;br /&gt;20                  type = "Menu"&lt;br /&gt;21                  label = "${res:Demo.Menu.File}"&gt;&lt;br /&gt;22      &lt;MenuItem id = "CmdBlack"&lt;br /&gt;23                      label = "Cmd&amp;amp;Black"&lt;br /&gt;24                      shortcut = "Control|B"&lt;br /&gt;25                      icon = "qq.face1"&lt;br /&gt;26                      class = "MainForm.CmdBlack"/&gt;&lt;br /&gt;27      &lt;Include id = "DynamicMenuList" path = "/michael/dymanic_Menus"/&gt;&lt;br /&gt;28      &lt;MenuItem id = "Separator1" type = "Separator"/&gt;&lt;br /&gt;29      &lt;MenuItem id = "Exit"&lt;br /&gt;30                      label = "E&amp;amp;xit"&lt;br /&gt;31                      shortcut = "Control|X"&lt;br /&gt;32                      class = "MainForm.CmdExit"/&gt;&lt;br /&gt;33    &lt;/MenuItem&gt;&lt;br /&gt;34    &lt;MenuItem id = "Manager"&lt;br /&gt;35                  type = "Menu"&lt;br /&gt;36                  label = "&amp;amp;Manager"&gt;&lt;br /&gt;37      &lt;Include id = "AddInManager" path = "/michael/AddInManager"/&gt;&lt;br /&gt;38    &lt;/MenuItem&gt;&lt;br /&gt;39  &lt;/Path&gt;&lt;br /&gt;40  &lt;Path name = "/michael/myToolbar"&gt;&lt;br /&gt;41    &lt;ToolbarItem id = "CmdBlack"&lt;br /&gt;42                     tooltip = "Black command"&lt;br /&gt;43                     icon = "qq.face1"&lt;br /&gt;44                     class = "MainForm.CmdBlack"/&gt;&lt;br /&gt;45    &lt;ToolbarItem id = "Separator1" type = "Separator"/&gt;&lt;br /&gt;46    &lt;ToolbarItem id = "Exit"&lt;br /&gt;47                      tooltip = "Exit the app"&lt;br /&gt;48                      icon = "CloseIcon"&lt;br /&gt;49                      class = "MainForm.CmdExit"/&gt;&lt;br /&gt;50  &lt;/Path&gt;&lt;br /&gt;51&lt;/AddIn&gt;&lt;AddIn&gt;节提供了插件的名称、作者、url、插件描述等信息&lt;br /&gt;&lt;Indetity&gt;提供了插件的唯一标识名称及版本，其它插件的配置文件可以引用该名称,如&lt;Dependency addin=...&gt;&lt;br /&gt;&lt;Import&gt;指向该插件引用的dll位置&lt;br /&gt;后面的形如&lt;Path name="..."&gt;&lt;MenuItem&gt;...&lt;/Path&gt;的是定义配置文件的核心数据，path节的name属性指明该节下的节点所处(在AddInTree中)的命名层次，节点下的MenuItem, ToolBarItem, FileFilter, Include等统称为Condon，各代表菜单项、工具栏按钮、文件过滤等，这些数据结构可以非常简单地被扩展、解析。&lt;br /&gt;注：&lt;br /&gt;addin配置文件中的 label = "${res:Demo.Menu.File}", icon = "qq.face1" 等属性值是指向资源文件的引用，资源文件见Entry项目的StrImgRes.resx&lt;br /&gt;&lt;br /&gt;4、SharpDevelop插件树中的重要概念&lt;br /&gt;Condon: 代表&lt;Path&gt;节下的一个（一般化）节点（如：&lt;MenuItem&gt;&lt;ToolBarItem&gt;...）统称为 Condon，该类含ID、Name、InsertBefore、InsertAfter、Conditions、Properties（类似于 HashTable的结构）等属性，配置节中的其它属性（除ID,Name,InsertBefore,InsertAfter外，如label, shortcut等）存储在Properties对象中。&lt;br /&gt;Doozer: 代表Condon节点的更具体的实例，如MenuItemDoozer, ToolBarItemDoozer, FileFilterDoozer, IncludeDoozer, FileFilterDoozer等，用以创建具体的object对象，可以扩展编写自定义的Doozer。&lt;br /&gt;&lt;br /&gt;5、Demo项目代码分析&lt;br /&gt;至此，我们大概能猜到SharpDevelop中的插件机制是怎样的，下面就结合Demo的分析来体验一下SharpDevelop的插件功能：&lt;br /&gt;MainForm.FrmMain.cs中使用单件模式获取此类，关键代码如下：&lt;br /&gt;FrmMain.cs&lt;br /&gt; 1using ICSharpCode.Core;&lt;br /&gt; 2&lt;br /&gt; 3// 变量声明&lt;br /&gt; 4const string _BoundProperty = "FormBounds";&lt;br /&gt; 5Label _lblMsg;&lt;br /&gt; 6MenuStrip _menuStrip;&lt;br /&gt; 7ToolStrip _toolStrip;&lt;br /&gt; 8//&lt;br /&gt; 9void IniFrm()&lt;br /&gt;10{&lt;br /&gt;11    // 设置窗体位置&lt;br /&gt;12    Rectangle rect = PropertyService.Get&lt;Rectangle&gt;(_BoundProperty, new Rectangle(10, 10, this.Width, this.Height));&lt;br /&gt;13    this.StartPosition = FormStartPosition.Manual;&lt;br /&gt;14    this.Bounds = rect;&lt;br /&gt;15    this.FormClosing += delegate&lt;br /&gt;16    {&lt;br /&gt;17        // 设置用户属性信息&lt;br /&gt;18        PropertyService.Set&lt;Rectangle&gt;(_BoundProperty, this.Bounds);&lt;br /&gt;19    };&lt;br /&gt;20&lt;br /&gt;21    _lblMsg = new Label();&lt;br /&gt;22    _lblMsg.Dock = DockStyle.Fill;&lt;br /&gt;23    _lblMsg.Font = new Font("Arial", 16, FontStyle.Bold);&lt;br /&gt;24    _lblMsg.Text = "App loaded!";&lt;br /&gt;25    this.Controls.Add(_lblMsg);&lt;br /&gt;26&lt;br /&gt;27    _toolStrip = ToolbarService.CreateToolStrip(this, "/michael/myToolbar");&lt;br /&gt;28    this.Controls.Add(_toolStrip);&lt;br /&gt;29&lt;br /&gt;30    _menuStrip = new MenuStrip();&lt;br /&gt;31    MenuService.AddItemsToMenu(_menuStrip.Items, this, "/michael/myMenus");&lt;br /&gt;32    this.Controls.Add(_menuStrip);&lt;br /&gt;33}&lt;br /&gt;34public void DrawMsg(string msg,Color color)&lt;br /&gt;35{&lt;br /&gt;36    _lblMsg.Text = msg;&lt;br /&gt;37    _lblMsg.ForeColor = color;&lt;br /&gt;38}主窗体的类中声明了Label, MenuStrip, ToolStrip 分别用以显示文字、菜单、工具栏。菜单、工具栏对象的获取通过ICSharpCode.Core内置类仅用简单的两行代码实现。此类中公开的 DrawMsg(...)方法用以向扩展菜单、工具栏按钮等提供公开可调用的功能。创建菜单、工具栏的两个方法中的一个重要参数是路径参数（分别是 "/michael/myToolbar"和"/michael/myMenus"），在前面的配置文件代码中可以找到相关定义节，其中相关节点一个重要属性是class, 该属性指定了（菜单、工具栏按钮的）相关类,其实现代码如下（MainForm项目的Commands.cs）：&lt;br /&gt;注：&lt;br /&gt;FrmMain 类的IniFrm()方法中前几行代码用以设置启动窗体的大小和位置，使用到了ICSharpCode.Core.PropertyService类，该类将配置文件保存在"C:\Documents and Settings\michael\Application Data\michael's add-in test\myCfgParas.xml"，其中[michael]是计算机名；[michael's add-in test]是应用程序名称，在程序启动时创建CoreStartup实例时指定；[myCfgParas.xml]由属性 CoreStartup.PropertiesName指定（详见后面Main()中的代码）。&lt;br /&gt;Commands.cs&lt;br /&gt; 1//using &lt;br /&gt; 2namespace MainForm&lt;br /&gt; 3{&lt;br /&gt; 4    public class CmdBlack : AbstractMenuCommand&lt;br /&gt; 5    {&lt;br /&gt; 6        public override void Run()&lt;br /&gt; 7        {&lt;br /&gt; 8            FrmMain frm = (FrmMain)this.Owner;&lt;br /&gt; 9&lt;br /&gt;10            StringBuilder sBuilder = new StringBuilder();&lt;br /&gt;11            ArrayList alDatas = AddInTree.BuildItems("/michael/BlackText", null, true);&lt;br /&gt;12            foreach (string str in alDatas)&lt;br /&gt;13                sBuilder.AppendLine("suported types:     " + str);&lt;br /&gt;14&lt;br /&gt;15            frm.DrawMsg(sBuilder.ToString(), Color.Black);&lt;br /&gt;16        }&lt;br /&gt;17    }&lt;br /&gt;18&lt;br /&gt;19    public class CmdExit : AbstractMenuCommand&lt;br /&gt;20    {&lt;br /&gt;21        public override void Run()&lt;br /&gt;22        {&lt;br /&gt;23            FrmMain frm = (FrmMain)this.Owner;&lt;br /&gt;24            if (MessageBox.Show("Sure to exit?","Info:",MessageBoxButtons.YesNoCancel,MessageBoxIcon.Question) == DialogResult.Yes)&lt;br /&gt;25                frm.Close();&lt;br /&gt;26        }&lt;br /&gt;27    }&lt;br /&gt;28}&lt;br /&gt;可以看到插件类必须实现ICommand接口或继承AbstractMenuCommand类，ICommand接口定义的Owner属性返回该对象的拥有者Object，在此例子中即FrmMain对象，CmdBlack类中通过((FrmMain)Owner).DrawMsg(...)向主窗体发出功能命令。&lt;br /&gt;至此，只剩下对ICSharpCode.Core进行必要的初始化配置了（参见Demo中的Entry项目Program.cs中的static void Main()函数）：&lt;br /&gt;void Main&lt;br /&gt; 1LoggingService.Info("Application start");&lt;br /&gt; 2Assembly asm = Assembly.GetExecutingAssembly();&lt;br /&gt; 3FileUtility.ApplicationRootPath = Path.GetDirectoryName(asm.Location);&lt;br /&gt; 4ResourceService.RegisterNeutralStrings(new ResourceManager("Entry.StrImgRes", asm));&lt;br /&gt; 5ResourceService.RegisterNeutralImages(new ResourceManager("Entry.StrImgRes", asm));&lt;br /&gt; 6&lt;br /&gt; 7LoggingService.Info("Starting core services");&lt;br /&gt; 8CoreStartup coreStartup = new CoreStartup("michael's add-in test");&lt;br /&gt; 9coreStartup.PropertiesName = "myCfgParas";&lt;br /&gt;10coreStartup.StartCoreServices();&lt;br /&gt;11// 在指定文件夹中搜寻插件的配置文件&lt;br /&gt;12coreStartup.AddAddInsFromDirectory(Path.Combine(FileUtility.ApplicationRootPath, "myAddIns"));&lt;br /&gt;13// AddinManager 插件的属性：保存用户禁用的插件信息&lt;br /&gt;14coreStartup.ConfigureExternalAddIns(Path.Combine(PropertyService.ConfigDirectory, "AddIns.xml"));&lt;br /&gt;15// AddinManager 插件的属性：保存用户安装的插件信息&lt;br /&gt;16coreStartup.ConfigureUserAddIns(Path.Combine(PropertyService.ConfigDirectory, "AddInInstallTemp"),&lt;br /&gt;17                                Path.Combine(PropertyService.ConfigDirectory, "AddIns"));&lt;br /&gt;18coreStartup.RunInitialization();&lt;br /&gt;19try&lt;br /&gt;20{&lt;br /&gt;21    LoggingService.Info("Running application");&lt;br /&gt;22    Application.Run(MainForm.FrmMain.Instance);&lt;br /&gt;23}catch{&lt;br /&gt;24&lt;br /&gt;注：&lt;br /&gt;Demo 项目引用的AddinManager也是SharpCode.Core中的一个插件实现，查看AddinManager.Addin，可见其定义了菜单项、新界面（点击新菜单时Run()方法中定义弹出的新窗体）、新界面的上下文菜单，上下文菜单中使用&lt;Condition&gt;配置菜单项何时可用……&lt;br /&gt;Demo项目中扩展菜单的例子参见Demo中的ExtenalMenus工程中的Command.cs和ExternalMenu.addin，该项目实现了两个新的菜单项，并且实现了一个自定义的Doozer。&lt;br /&gt;&lt;br /&gt;6、总结：&lt;br /&gt;a, ICSharpCode.Core默认实现的Doozer&lt;br /&gt;Class        根据配置文件的声明由System.Reflection创建出相关对象&lt;br /&gt;FileFilter    创建出路径后缀名的过滤选项提供给OpenFileDialog或是SaveFileDialog使用&lt;br /&gt;Include    向addin tree引进一个（使用item属性）或多个（使用path属性）子项&lt;br /&gt;Icon        用以创建文件类型与图标间的关联&lt;br /&gt;MenuItem    创建菜单项 type可为：Seperator, CheckBox, Item/Command, Menu, Builder&lt;br /&gt;ToolBarItem    创建工具栏按钮荐 type可为：Seperator, CheckBox, Item, ComboBox, DropDownButton&lt;br /&gt;&lt;br /&gt;b, 配置文件中引用预定义资源格式&lt;br /&gt;${res:ResourceName}        引用ResourceService系统资源&lt;br /&gt;${property:PropertyName}    引用PropertyService中的属性&lt;br /&gt;${env:VariableName}        引用系统变量&lt;br /&gt;${exe:ProperName}        引用整个程序集的属性&lt;br /&gt;&lt;br /&gt;c, Condition&lt;br /&gt;[略（有待进一步分析）]&lt;br /&gt;&lt;br /&gt;7、相关资料：&lt;br /&gt;《Dissecting a C# Application Inside SharpDevelop.pdf》&lt;br /&gt;SharpDevelop源代码(\src\ 和 \samples\ICSharpCode.Core.Demo\)&lt;br /&gt;http://www.sharpdevelop.com/OpenSource/SD/Default.aspx&lt;br /&gt;http://www.codeproject.com/csharp/ICSharpCodeCore.asp &lt;br /&gt;&lt;br /&gt;SharpDevelop浅析_2_User Interface&lt;br /&gt;&lt;br /&gt;创建易扩展且功能模块松散耦合的应用程序&lt;br /&gt;&lt;br /&gt;2、相关概念：&lt;br /&gt;主窗体部分：              Workbench&lt;br /&gt;磁盘文件查看窗口：    Pad&lt;br /&gt;文件查看窗口：         ViewContent&lt;br /&gt;说明：&lt;br /&gt;Pad可以使用ICSharpCode.Core的Addin插件机制来扩充Pad，如Visual Studio的资源管理器、类查看器、属性窗口、消息窗口等都属于Pad&lt;br /&gt;ViewContent同样支持插件扩充，根据不同的文件类型使用不同的控件来处理显示，Demo中已实现的文件类型支持：网页文件、图片、普通文本，Visual Studio中的代码窗口、窗体设计器、资源编辑器、对象查看器等都属于ViewContent&lt;br /&gt;Workbench与WorkbenchLayout结合使用来控制主窗口的外观显示，如普通的MDI(PhotoShop?)或Demo使用的WeifenLuo.WinFormsUI.Docking显示方式……&lt;br /&gt;&lt;br /&gt;3、Demo代码分析&lt;br /&gt;(注：下面的分析前提是你已经了解如何使用ICSharpCode.Core的Addin插件机制)&lt;br /&gt;通过上面的界面及功能说明，可以确定程序至少应包括接口声明、基本实现两个项目，而接口中又分为：Pad接口、ViewContent接口、Workbench接口，这样的程序设计重点与难点在哪呢？思考后的结果应该是接口，从接口中能看到程序各部分是如何交互的，以及插件的扩展点，接口的设计好坏决定着程序的易维护性与易扩展性，所以下面就重点看接口的定义(附介绍相关对象的创建等)：&lt;br /&gt;&lt;br /&gt;Pad接口&lt;br /&gt; 1//  Core|Interface 定义部分：&lt;br /&gt; 2public interface IPadContent : IDisposable&lt;br /&gt; 3{&lt;br /&gt; 4    System.Windows.Forms.Control Control { get; }&lt;br /&gt; 5    &lt;br /&gt; 6    void RedrawContent();&lt;br /&gt; 7}&lt;br /&gt; 8public class PadDescriptor : IDisposable&lt;br /&gt; 9{&lt;br /&gt;10    Codon       codon;&lt;br /&gt;11    IPadContent padContent;&lt;br /&gt;12    bool        padContentCreated;&lt;br /&gt;13    &lt;br /&gt;14    public string Title {&lt;br /&gt;15        get {&lt;br /&gt;16            return codon.Properties["title"];&lt;br /&gt;17        }&lt;br /&gt;18    }&lt;br /&gt;19    public string Icon {&lt;br /&gt;20        get {&lt;br /&gt;21            return codon.Properties["icon"];&lt;br /&gt;22        }&lt;br /&gt;23    }&lt;br /&gt;24    public string Class {&lt;br /&gt;25        get {&lt;br /&gt;26            return codon.Properties["class"];&lt;br /&gt;27        }&lt;br /&gt;28    }&lt;br /&gt;29    public IPadContent PadContent {&lt;br /&gt;30        get {&lt;br /&gt;31            CreatePad();&lt;br /&gt;32            return padContent;&lt;br /&gt;33        }&lt;br /&gt;34    }&lt;br /&gt;35    public void CreatePad()&lt;br /&gt;36    {&lt;br /&gt;37        if (!padContentCreated) {&lt;br /&gt;38            padContentCreated = true;&lt;br /&gt;39            padContent = (IPadContent)codon.AddIn.CreateObject(Class);&lt;br /&gt;40        }&lt;br /&gt;41    }&lt;br /&gt;42    //省略部分方法、属性&lt;br /&gt;43    public PadDescriptor(Codon codon)&lt;br /&gt;44    {&lt;br /&gt;45        this.codon = codon;&lt;br /&gt;46    }&lt;br /&gt;47}&lt;br /&gt;48//  Gui项目中的实现&lt;br /&gt;49class PadContentWrapper : DockContent&lt;br /&gt;50{&lt;br /&gt;51    PadDescriptor padDescriptor;    //通过此对象来获取相关属性&lt;br /&gt;52    //&lt;br /&gt;53}看到IPadContent接口返回一个WinForm的Control控件，此控件在实现时被相应的窗体获取并适当地显示，Demo中的磁盘查看器Pad返回的Control是一个UserConrol,使用了TreeView和ListView组合。注意IPadContent接口中定义返回一个Control而非Form是很聪明的技巧，可以看到实现端的PadContentWrapper继承自WeifenLuo.WinFormsUI.DockContent,这依赖于实现端的表现方式，而接口可以不受影响。PadDescriptor是个辅助类，用以返回Pad相关的属性信息，包括返回IPadContent的实例对象。&lt;br /&gt;接下来看Pad的xml声明及客户端调用：&lt;br /&gt;Pad声明及使用&lt;br /&gt; 1//取自Entry项目的SD_UI.addin&lt;br /&gt; 2&lt;Path name = "/SharpDevelop/Workbench/Pads"&gt;&lt;br /&gt; 3    &lt;!--&lt;br /&gt; 4    ProjectBrowser&lt;br /&gt; 5    ClassBrowser&lt;br /&gt; 6    SideBar&lt;br /&gt; 7    ErrorList&lt;br /&gt; 8    TaskList&lt;br /&gt; 9    CompilerMessageView&lt;br /&gt;10    PropertyPad&lt;br /&gt;11    SearchResults&lt;br /&gt;12    Bookmarks&lt;br /&gt;13    DefinitionView&lt;br /&gt;14    &lt;br /&gt;15    --&gt;&lt;br /&gt;16    &lt;Pad id       = "FileScout"&lt;br /&gt;17         category = "Tools"&lt;br /&gt;18         title    = "${res:MainWindow.Windows.FileScoutLabel}"&lt;br /&gt;19         icon     = "PadIcons.FileBrowser"&lt;br /&gt;20         shortcut = "Control|Alt|F"&lt;br /&gt;21         class    = "SDUserInterface.GUI.Pad.FileScout"/&gt;&lt;br /&gt;22&lt;/Path&gt;&lt;br /&gt;23// 取自Gui项目的DefaultWorkbench.cs&lt;br /&gt;24void InitializeWorkspace()&lt;br /&gt;25{&lt;br /&gt;26    //&lt;br /&gt;27    ArrayList contents = AddInTree.GetTreeNode("/SharpDevelop/Workbench/Pads").BuildChildItems(this);&lt;br /&gt;28    foreach (PadDescriptor content in contents)&lt;br /&gt;29    {&lt;br /&gt;30        if (content != null)&lt;br /&gt;31        {&lt;br /&gt;32            ShowPad(content);&lt;br /&gt;33        }&lt;br /&gt;34    }&lt;br /&gt;35    //&lt;br /&gt;36}&lt;br /&gt;配置文件中的class指定了实现IPadContent的一个类型(全称限定名)，使用时通过ICSharpCode.Core的AddInTree对象构建相关PadDescriptor集合……&lt;br /&gt;&lt;br /&gt;下面来看ViewContent的定义：&lt;br /&gt;&lt;br /&gt;ViewContent接口&lt;br /&gt; 1// Core|Interface 定义部分：&lt;br /&gt; 2public interface IViewContent : IDisposable&lt;br /&gt; 3{&lt;br /&gt; 4    Control Control { get; set; }&lt;br /&gt; 5&lt;br /&gt; 6    IWorkbenchWindow WorkbenchWindow { get; set; }&lt;br /&gt; 7&lt;br /&gt; 8    string TitleName { get; set; }&lt;br /&gt; 9&lt;br /&gt;10    string FileName { get; set; }&lt;br /&gt;11&lt;br /&gt;12    bool IsReadOnly { get; }&lt;br /&gt;13&lt;br /&gt;14    void Load(string fileName);&lt;br /&gt;15&lt;br /&gt;16    event EventHandler TitleNameChanged;&lt;br /&gt;17}&lt;br /&gt;18public class DisplayBindingDescriptor&lt;br /&gt;19{&lt;br /&gt;20    object binding = null;&lt;br /&gt;21    Codon codon;&lt;br /&gt;22    &lt;br /&gt;23    public IDisplayBinding Binding {&lt;br /&gt;24        get {&lt;br /&gt;25            if (binding == null) {&lt;br /&gt;26                binding = codon.AddIn.CreateObject(codon.Properties["class"]);&lt;br /&gt;27            }&lt;br /&gt;28            return binding as IDisplayBinding;&lt;br /&gt;29        }&lt;br /&gt;30    }&lt;br /&gt;31    &lt;br /&gt;32    public Codon Codon {&lt;br /&gt;33        get {&lt;br /&gt;34            return codon;&lt;br /&gt;35        }&lt;br /&gt;36    }&lt;br /&gt;37    &lt;br /&gt;38    public DisplayBindingDescriptor(Codon codon)&lt;br /&gt;39    {&lt;br /&gt;40        this.codon = codon;&lt;br /&gt;41    }&lt;br /&gt;42    &lt;br /&gt;43    public bool CanAttachToFile(string fileName)&lt;br /&gt;44    {&lt;br /&gt;45        string fileNameRegex = codon.Properties["fileNamePattern"];&lt;br /&gt;46        if (fileNameRegex == null || fileNameRegex.Length == 0) // no regex specified&lt;br /&gt;47            return true;&lt;br /&gt;48        return Regex.IsMatch(fileName, fileNameRegex, RegexOptions.IgnoreCase);&lt;br /&gt;49    }&lt;br /&gt;50}&lt;br /&gt;51public interface IDisplayBinding&lt;br /&gt;52{&lt;br /&gt;53    bool CanCreateContentForFile(string fileName);&lt;br /&gt;54    &lt;br /&gt;55    IViewContent CreateContentForFile(string fileName);&lt;br /&gt;56}&lt;br /&gt;57// Gui项目中的实现：&lt;br /&gt;58public class SdiWorkspaceWindow : DockContent, IWorkbenchWindow&lt;br /&gt;59{&lt;br /&gt;60    IViewContent content;&lt;br /&gt;61    //&lt;br /&gt;62}&lt;br /&gt;可以看到IViewContent同样是返回一个Conrol，供使用端(SdiWorkspaceWindow)根据需要封装组合；DisplayBindingDescriptor同样是个辅助类，除了返回ViewContent的相关属性信息外，提供了bool CanAttachToFile(string fileName)方法，用以判断当前显示插件是否可以显示相关类型的文件，这里的判断是通过配置文件中的fileNamePattern属性作正则判断(注：文件名称符合一定规则的可能会用到此属性，一般不常用)，注意到该辅助类返回了一个IDisplayBinding接口，查看该接口的方法可以看到使用它来更进一步地判断当前文件是否是可支持类型(通过文件扩展名或试读取等方式)，如果属于该插件支持类型的文件则创建并返回IViewContenet接口。ViewContent插件的声明如下：&lt;br /&gt;&lt;br /&gt;ViewContent插件声明&lt;br /&gt; 1&lt;Path name = "/SharpDevelop/Workbench/DisplayBindings"&gt;&lt;br /&gt; 2    &lt;DisplayBinding id               = "Browser"&lt;br /&gt; 3                    supportedformats = "Web Pages"&lt;br /&gt; 4                    class            = "SDUserInterface.GUI.ViewContent.BrowserDisplayBinding"/&gt;&lt;br /&gt; 5    &lt;DisplayBinding id    = "Text"&lt;br /&gt; 6                        insertafter = "Browser"&lt;br /&gt; 7                        supportedformats = "Text Files,Source Files"&lt;br /&gt; 8                        class = "SDUserInterface.GUI.ViewContent.TextViewDisplayBinding" /&gt;&lt;br /&gt; 9    &lt;DisplayBinding id    = "Image"&lt;br /&gt;10                        insertbefore = "Text"&lt;br /&gt;11                        supportedformats = "图片"&lt;br /&gt;12                        class = "SDUserInterface.GUI.ViewContent.ImageDisplayBinding" /&gt;&lt;br /&gt;13&lt;/Path&gt;&lt;br /&gt;值得注意的是insertbefore, insertafter 属性，此属性指明获取所有DisplayBindingDescriptor后的先后顺序，如：一个.rtf文件可以由Office-Word和记事本打开，一般要优先选择使用Word打开。&lt;br /&gt;获取ViewContent对象的过程如下：双击磁盘文件Pad中的一个文件项时，调用FileService中的OpenFile(string fileName)方法，相关代码如下：&lt;br /&gt;&lt;br /&gt;获取/使用ViewContent&lt;br /&gt; 1// 取自Gui项目中的Common/FileService.cs&lt;br /&gt; 2public static IWorkbenchWindow OpenFile(string fileName)&lt;br /&gt; 3{&lt;br /&gt; 4    //&lt;br /&gt; 5    IDisplayBinding binding = DisplayBindingService.GetBindingPerFileName(fileName);&lt;br /&gt; 6    &lt;br /&gt; 7    if (binding != null) {&lt;br /&gt; 8        binding.CreateContentForFile(fileName);&lt;br /&gt; 9        WorkbenchSingleton.Workbench.ShowView(newContent);&lt;br /&gt;10        //&lt;br /&gt;11    } else {&lt;br /&gt;12        throw new ApplicationException("Can't open " + fileName + ", no display codon found.");&lt;br /&gt;13    }&lt;br /&gt;14    return GetOpenFile(fileName);&lt;br /&gt;15}&lt;br /&gt;16// 取自Gui项目中的Common/DisplayBindingService.cs&lt;br /&gt;17static DisplayBindingDescriptor GetCodonPerFileName(string filename)&lt;br /&gt;18{&lt;br /&gt;19    foreach (DisplayBindingDescriptor binding in bindings) {&lt;br /&gt;20        if (binding.CanAttachToFile(filename)) {&lt;br /&gt;21            if (binding.Binding != null &amp;&amp; binding.Binding.CanCreateContentForFile(filename)) {&lt;br /&gt;22                return binding;&lt;br /&gt;23            }&lt;br /&gt;24        }&lt;br /&gt;25    }&lt;br /&gt;26    return null;&lt;br /&gt;27}&lt;br /&gt;接下来看主窗体的定义：&lt;br /&gt;&lt;br /&gt;Workbench接口&lt;br /&gt; 1public interface IWorkbench&lt;br /&gt; 2{&lt;br /&gt; 3    string Title  { get; set; }&lt;br /&gt; 4&lt;br /&gt; 5    List&lt;IViewContent&gt; ViewContentCollection { get; }&lt;br /&gt; 6&lt;br /&gt; 7    List&lt;PadDescriptor&gt; PadContentCollection { get; }&lt;br /&gt; 8&lt;br /&gt; 9    IWorkbenchWindow ActiveWorkbenchWindow { get; }&lt;br /&gt;10    &lt;br /&gt;11    object ActiveContent { get; }&lt;br /&gt;12    &lt;br /&gt;13    IWorkbenchLayout WorkbenchLayout { get; set; }&lt;br /&gt;14    &lt;br /&gt;15    void ShowView(IViewContent content);&lt;br /&gt;16&lt;br /&gt;17    void CloseAllViews();&lt;br /&gt;18    &lt;br /&gt;19    void CloseView(IViewContent content);&lt;br /&gt;20    &lt;br /&gt;21    void ShowPad(PadDescriptor content);&lt;br /&gt;22    &lt;br /&gt;23    PadDescriptor GetPad(Type type);&lt;br /&gt;24&lt;br /&gt;25    void RedrawAllComponents();&lt;br /&gt;26}&lt;br /&gt;27public interface IWorkbenchLayout&lt;br /&gt;28{&lt;br /&gt;29    bool FullScreen { get; set; }&lt;br /&gt;30&lt;br /&gt;31    IWorkbenchWindow ActiveWorkbenchwindow { get; }&lt;br /&gt;32&lt;br /&gt;33    object ActiveContent { get; }&lt;br /&gt;34    &lt;br /&gt;35    void Attach(IWorkbench workbench);&lt;br /&gt;36    &lt;br /&gt;37    void Detach();&lt;br /&gt;38    &lt;br /&gt;39    void ShowPad(PadDescriptor content);&lt;br /&gt;40&lt;br /&gt;41    void ShowPad(PadDescriptor content,bool bActivateIt);&lt;br /&gt;42    &lt;br /&gt;43    IWorkbenchWindow ShowView(IViewContent content);&lt;br /&gt;44&lt;br /&gt;45    void RedrawAllComponents();&lt;br /&gt;46&lt;br /&gt;47    void LoadConfiguration();&lt;br /&gt;48    void StoreConfiguration();&lt;br /&gt;49}&lt;br /&gt;IWorkbench定义主窗体，IWorkbenchLayout定义窗体布局，可以看到IWorkbench的两个重要属性是Pad和ViewContent的对象集合(维护已打开的窗体记录，避免重复打开等作用)，其实现类的ShowPad()/ShowView()方法执行的操作即向对应的集合添加成员，然后调用IWorkbenchLayout的ShowPad()/ShowView()。IWorkbenchLayout的LoadConfiguration()和StoreConfiguration()方法用以在窗体加载或关闭时执行加载或保存子窗口布局的操作。&lt;br /&gt;&lt;br /&gt;至此Demo的核心已分析完了，我们可以根据定义的接口扩展程序，如增加项目管理/查看Pad, 增加.swf等文件查看的ViewContent， 或更换主界面显示为普通MDI方式……&lt;br /&gt;&lt;br /&gt;4、总结：&lt;br /&gt;此Demo更说明了ICSharpCode.Core的插件支持可以应用到很多的方面：&lt;br /&gt;a, 界面组成部分Pad&lt;br /&gt;b, 界面中不同类型的文件查看器ViewContent&lt;br /&gt;c, 磁盘文件查看Pad的下侧文件列表针对不同文件显示相关图标(详见SD_UI.addin文件的"/Workspace/Icons"层次下的定义)&lt;br /&gt;...&lt;br /&gt;SharpDevelop的这种界面设计方案使得应用程序很容易扩展和进一步开发，而不与已开发的模块冲突；从中得到的启发是应用程序要重点设计接口(契约)以及处理对象间的关系……&lt;br /&gt;&lt;br /&gt;说明：Demo代码基本来源于SharpDevelop源码，删改了部分代码以使Demo精简和突出重点。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SharpDevelop浅析_3_Internationalization &amp; TextEditor&lt;br /&gt;&lt;br /&gt;国际化、文档编辑器、语法高亮显示&lt;br /&gt;&lt;br /&gt;2、SharpDevelop的Internationalization的使用&lt;br /&gt;多语言的实现就是在显示时根据键获取相应语言环境下的键值(Dictionary&lt;key,value&gt;)，因此在编写程序时应该引用键，而非直接书写要显示的字符。一般地，应用程序的显示包括菜单、状态栏、提示字符等，因此Demo中的主菜单在配置文件(参见Basic.addin)中使用label = "${res:Menu.File.Open}"，退出应用程序的提示字符使用string s = StringParser.Parse("${res:Info.Exit}");。ICSharpCode.Core.dll支持语言环境的实时修改(修改后语言设置不需重启应用程序)，因此要在应用程序订阅语言环境改变的事件，相关代码如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;语言环境的修改及事件响应&lt;br /&gt; 1//a, 设置语言&lt;br /&gt; 2//引自SharpPad项目的Dialogs\SelectCulturePanel.cs&lt;br /&gt; 3public override bool ReceiveDialogMessage(DialogMessage message)&lt;br /&gt; 4{&lt;br /&gt; 5    if (message == DialogMessage.OK) {&lt;br /&gt; 6        if (SelectedCulture != null) {&lt;br /&gt; 7            PropertyService.Set("CoreProperties.UILanguage", SelectedCulture);&lt;br /&gt; 8        }&lt;br /&gt; 9    }&lt;br /&gt;10    return true;&lt;br /&gt;11}&lt;br /&gt;12//返回当前窗体用户选择的语言设置(从显示国家国旗的ListView控件)&lt;br /&gt;13string SelectedCulture {&lt;br /&gt;14    get {&lt;br /&gt;15        if (listView.SelectedItems.Count &gt; 0) {&lt;br /&gt;16            return listView.SelectedItems[0].SubItems[1].Text;&lt;br /&gt;17        }&lt;br /&gt;18        return null;&lt;br /&gt;19    }&lt;br /&gt;20}&lt;br /&gt;21//b, 刷新当前应用程序&lt;br /&gt;22//引自SharpPad项目的SharpPad.cs&lt;br /&gt;23void IniFrm()&lt;br /&gt;24{&lt;br /&gt;25    //&lt;br /&gt;26    _menuStrip = new MenuStrip();&lt;br /&gt;27    MenuService.AddItemsToMenu(_menuStrip.Items, this, "/michael/myMenus");&lt;br /&gt;28    this.Controls.Add(_menuStrip);&lt;br /&gt;29&lt;br /&gt;30    PropertyService.PropertyChanged += new PropertyChangedEventHandler(PropertyService_PropertyChanged);&lt;br /&gt;31    ResourceService.LanguageChanged += delegate{&lt;br /&gt;32        //更新菜单项的Text显示&lt;br /&gt;33        foreach (ToolStripItem item in _menuStrip.Items)&lt;br /&gt;34        {&lt;br /&gt;35            if (item is IStatusUpdate)&lt;br /&gt;36            {&lt;br /&gt;37                ((IStatusUpdate)item).UpdateText();&lt;br /&gt;38            }&lt;br /&gt;39        }&lt;br /&gt;40    };&lt;br /&gt;41}&lt;br /&gt;42//引自ICSharpCode.Core的src\AddinTree\Addin\DefaultDoozers\MenuItem\Gui\IStatusUpdate.Core&lt;br /&gt;43using System;&lt;br /&gt;44namespace ICSharpCode.Core&lt;br /&gt;45{&lt;br /&gt;46    public interface IStatusUpdate&lt;br /&gt;47    {&lt;br /&gt;48        void UpdateStatus();&lt;br /&gt;49        void UpdateText();&lt;br /&gt;50    }&lt;br /&gt;51}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;另外，可以看到Demo中的选项命令窗口也采用了插件模式来构造窗体(实现细节就不多谈了)，容器窗体是TreeViewOption，插件窗体如：SelectCulturePanel, SelectStylePanel, DemoNothing，真是“扩展--无处不在”呀。SharpDevelop源码中的这些窗体的成员控件是通过.xfrm配置文件配置，窗体继承自XmlUserControl来根据配置文件生成控件，有一定的灵活性。&lt;br /&gt;新的语言包资源文件放在\data\resources\目录下(如StringResources.cn-gb.resources)，注意应用程序默认语言选项以及在未找到相关语言资源时都是引用Entry中的myRes.resx资源文件；语言声明文件是\data\resources\languages\LanguageDefinition.xml，其格式如下：&lt;br /&gt;LanguageDefinition.xml&lt;br /&gt;1&lt;Languages&gt;&lt;br /&gt;2    &lt;Languages name="Chinese (GB)"                  code="cn-gb"    page=""  icon="chinalg.png" /&gt;&lt;br /&gt;3    &lt;Languages name="German"                        code="de"       page=""  icon="germany.png" /&gt;&lt;br /&gt;4    &lt;Languages name="English"                 code="en"       page=""  icon="uk.png" /&gt;&lt;br /&gt;5&lt;/Languages&gt;&lt;br /&gt;SharpPad中动态显示可选语言项的分析类是LanguageService.cs和Language.cs，此处就不多解释了。&lt;br /&gt;&lt;br /&gt;3、SharpDevelop的Internationalization的实现分析&lt;br /&gt;SharpDevelop的多语言支持的键值对是通过本地资源文件存储的，当Demo中更改语言环境设置时，引发ICSharpCode.Core.dll中的事件及方法顺序如下：&lt;br /&gt;PropertyService类的属性更新引发PropertyChanged事件  -&gt;  ResourceService响应接收到的事件并重新加载保存在内存中的资源键值对，然后引发LanguageChanged事件（由使用端接收并作相关处理，如Demo中的SharpPad.cs中的事件订阅/处理）属性更新的相关代码如下：&lt;br /&gt;属性更改&lt;br /&gt; 1//PropertyService类实际是提供了对Properties类的包装，因此直接看Properties类中的代码：&lt;br /&gt; 2//引自ICSharpCode.Core\src\Services\PropertService\Properties.cs&lt;br /&gt; 3public void Set&lt;T&gt;(string property, T value)&lt;br /&gt; 4{&lt;br /&gt; 5    T oldValue = default(T);&lt;br /&gt; 6    if (!properties.ContainsKey(property)) {&lt;br /&gt; 7        properties.Add(property, value);&lt;br /&gt; 8    } else {&lt;br /&gt; 9        oldValue = Get&lt;T&gt;(property, value);&lt;br /&gt;10        properties[property] = value;&lt;br /&gt;11    }&lt;br /&gt;12    OnPropertyChanged(new PropertyChangedEventArgs(this, property, oldValue, value));&lt;br /&gt;13}&lt;br /&gt;14protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)&lt;br /&gt;15{&lt;br /&gt;16    if (PropertyChanged != null) {&lt;br /&gt;17        PropertyChanged(this, e);&lt;br /&gt;18    }&lt;br /&gt;19}&lt;br /&gt;20public delegate void PropertyChangedEventHandler(object sender, PropertyChangedEventArgs e);&lt;br /&gt;21public event PropertyChangedEventHandler PropertyChanged;&lt;br /&gt;资源服务类的事件响应代码如下：&lt;br /&gt;ResourceService类的事件响应&lt;br /&gt; 1//引自ICSharpCode.Core\src\Services\ResourceService\ResourceService.cs&lt;br /&gt; 2//首先在类的初始化中订阅属性更改事件：&lt;br /&gt; 3PropertyService.PropertyChanged += new PropertyChangedEventHandler(OnPropertyChange);&lt;br /&gt; 4//类级别变量：&lt;br /&gt; 5static Hashtable localStrings = null;&lt;br /&gt; 6static Hashtable localIcons   = null;&lt;br /&gt; 7public static event EventHandler LanguageChanged;&lt;br /&gt; 8//事件响应：&lt;br /&gt; 9static void OnPropertyChange(object sender, PropertyChangedEventArgs e)&lt;br /&gt;10{&lt;br /&gt;11    if (e.Key == uiLanguageProperty &amp;&amp; e.NewValue != e.OldValue) {&lt;br /&gt;12        LoadLanguageResources((string)e.NewValue);&lt;br /&gt;13        if (LanguageChanged != null)&lt;br /&gt;14            LanguageChanged(null, e);&lt;br /&gt;15    }&lt;br /&gt;16}&lt;br /&gt;17static void LoadLanguageResources(string language)&lt;br /&gt;18{&lt;br /&gt;19    try&lt;br /&gt;20    {&lt;br /&gt;21        Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(language);&lt;br /&gt;22    }&lt;br /&gt;23    catch (Exception)&lt;br /&gt;24    {&lt;br /&gt;25        try&lt;br /&gt;26        {&lt;br /&gt;27            Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(language.Split('-')[0]);&lt;br /&gt;28        }&lt;br /&gt;29        catch (Exception) { }&lt;br /&gt;30    }&lt;br /&gt;31&lt;br /&gt;32    localStrings = Load(stringResources, language);&lt;br /&gt;33    if (localStrings == null &amp;&amp; language.IndexOf('-') &gt; 0)&lt;br /&gt;34    {&lt;br /&gt;35        localStrings = Load(stringResources, language.Split('-')[0]);&lt;br /&gt;36    }&lt;br /&gt;37&lt;br /&gt;38    localIcons = Load(imageResources, language);&lt;br /&gt;39    if (localIcons == null &amp;&amp; language.IndexOf('-') &gt; 0)&lt;br /&gt;40    {&lt;br /&gt;41        localIcons = Load(imageResources, language.Split('-')[0]);&lt;br /&gt;42    }&lt;br /&gt;43&lt;br /&gt;44    localStringsResMgrs.Clear();&lt;br /&gt;45    localIconsResMgrs.Clear();&lt;br /&gt;46    currentLanguage = language;&lt;br /&gt;47    foreach (ResourceAssembly ra in resourceAssemblies)&lt;br /&gt;48    {&lt;br /&gt;49        ra.Load();&lt;br /&gt;50    }&lt;br /&gt;51}&lt;br /&gt;52static Hashtable Load(string name, string language)&lt;br /&gt;53{&lt;br /&gt;54    return Load(resourceDirectory + Path.DirectorySeparatorChar + name + "." + language + ".resources");&lt;br /&gt;55}&lt;br /&gt;56static Hashtable Load(string fileName)&lt;br /&gt;57{&lt;br /&gt;58    if (File.Exists(fileName)) {&lt;br /&gt;59        Hashtable resources = new Hashtable();&lt;br /&gt;60        ResourceReader rr = new ResourceReader(fileName);&lt;br /&gt;61        foreach (DictionaryEntry entry in rr) {&lt;br /&gt;62            resources.Add(entry.Key, entry.Value);&lt;br /&gt;63        }&lt;br /&gt;64        rr.Close();&lt;br /&gt;65        return resources;&lt;br /&gt;66    }&lt;br /&gt;67    return null;&lt;br /&gt;68}&lt;br /&gt;&lt;br /&gt;4、SharpDevelop的文档管理的基本概念&lt;br /&gt;代码编写工具的核心是代码编辑窗口(如打开一个.cs文件的窗口)，如何在应用程序中存储该窗口内的字符内容？有些文件可能有上千行，统计下来可能有过万个字符，如果使用string对象存储字符内容，显然是不能满足性能要求，而且要实现语法高亮显示的话，还需要区分存储TextWord和相应颜色……&lt;br /&gt;先看一下字符管理的基本要求：&lt;br /&gt;ITextBufferStrategy接口&lt;br /&gt; 1//引自ICSharpCode.TextEditor\src\Document\TextBufferStrategy\ITextBufferStrategy.cs&lt;br /&gt; 2namespace ICSharpCode.TextEditor.Document&lt;br /&gt; 3{&lt;br /&gt; 4    /**//// &lt;summary&gt;&lt;br /&gt; 5    /// Interface to describe a sequence of characters that can be edited.     &lt;br /&gt; 6    /// &lt;/summary&gt;&lt;br /&gt; 7    public interface ITextBufferStrategy&lt;br /&gt; 8    {&lt;br /&gt; 9        /**//// &lt;value&gt;&lt;br /&gt;10        /// The current length of the sequence of characters that can be edited.&lt;br /&gt;11        /// &lt;/value&gt;&lt;br /&gt;12        int Length {&lt;br /&gt;13            get;&lt;br /&gt;14        }&lt;br /&gt;15        &lt;br /&gt;16        /**//// &lt;summary&gt;&lt;br /&gt;17        /// Inserts a string of characters into the sequence.&lt;br /&gt;18        /// &lt;/summary&gt;&lt;br /&gt;19        /// &lt;param name="offset"&gt;&lt;br /&gt;20        /// offset where to insert the string.&lt;br /&gt;21        /// &lt;/param&gt;&lt;br /&gt;22        /// &lt;param name="text"&gt;&lt;br /&gt;23        /// text to be inserted.&lt;br /&gt;24        /// &lt;/param&gt;&lt;br /&gt;25        void Insert(int offset, string text);&lt;br /&gt;26        &lt;br /&gt;27        /**//// &lt;summary&gt;&lt;br /&gt;28        /// Removes some portion of the sequence.&lt;br /&gt;29        /// &lt;/summary&gt;&lt;br /&gt;30        /// &lt;param name="offset"&gt;&lt;br /&gt;31        /// offset of the remove.&lt;br /&gt;32        /// &lt;/param&gt;&lt;br /&gt;33        /// &lt;param name="length"&gt;&lt;br /&gt;34        /// number of characters to remove.&lt;br /&gt;35        /// &lt;/param&gt;&lt;br /&gt;36        void Remove(int offset, int length);&lt;br /&gt;37        &lt;br /&gt;38        /**//// &lt;summary&gt;&lt;br /&gt;39        /// Replace some portion of the sequence.&lt;br /&gt;40        /// &lt;/summary&gt;&lt;br /&gt;41        /// &lt;param name="offset"&gt;&lt;br /&gt;42        /// offset.&lt;br /&gt;43        /// &lt;/param&gt;&lt;br /&gt;44        /// &lt;param name="length"&gt;&lt;br /&gt;45        /// number of characters to replace.&lt;br /&gt;46        /// &lt;/param&gt;&lt;br /&gt;47        /// &lt;param name="text"&gt;&lt;br /&gt;48        /// text to be replaced with.&lt;br /&gt;49        /// &lt;/param&gt;&lt;br /&gt;50        void Replace(int offset, int length, string text);&lt;br /&gt;51        &lt;br /&gt;52        /**//// &lt;summary&gt;&lt;br /&gt;53        /// Fetches a string of characters contained in the sequence.&lt;br /&gt;54        /// &lt;/summary&gt;&lt;br /&gt;55        /// &lt;param name="offset"&gt;&lt;br /&gt;56        /// Offset into the sequence to fetch&lt;br /&gt;57        /// &lt;/param&gt;&lt;br /&gt;58        /// &lt;param name="length"&gt;&lt;br /&gt;59        /// number of characters to copy.&lt;br /&gt;60        /// &lt;/param&gt;&lt;br /&gt;61        string GetText(int offset, int length);&lt;br /&gt;62        &lt;br /&gt;63        /**//// &lt;summary&gt;&lt;br /&gt;64        /// Returns a specific char of the sequence.&lt;br /&gt;65        /// &lt;/summary&gt;&lt;br /&gt;66        /// &lt;param name="offset"&gt;&lt;br /&gt;67        /// Offset of the char to get.&lt;br /&gt;68        /// &lt;/param&gt;&lt;br /&gt;69        char GetCharAt(int offset);&lt;br /&gt;70        &lt;br /&gt;71        /**//// &lt;summary&gt;&lt;br /&gt;72        /// This method sets the stored content.&lt;br /&gt;73        /// &lt;/summary&gt;&lt;br /&gt;74        /// &lt;param name="text"&gt;&lt;br /&gt;75        /// The string that represents the character sequence.&lt;br /&gt;76        /// &lt;/param&gt;&lt;br /&gt;77        void SetContent(string text);&lt;br /&gt;78    }&lt;br /&gt;79}&lt;br /&gt;SharpDevelop采用的策略是使用带Gap的字符，Gap的长度小于预定规格时，按约定增加一定长度(有些类似于SqlServer的表空间管理?)，插入/修改/删除字符时只是修改Gap的长度和位置和移动部分字符，核心函数如下：&lt;br /&gt;GapTextBufferStrategy类&lt;br /&gt; 1//引自ICSharpCode.TextEditor\src\Document\TextBufferStrategy\GapTextBufferStrategy.cs&lt;br /&gt; 2//类级别变量：&lt;br /&gt; 3char[] buffer = new char[0];&lt;br /&gt; 4int gapBeginOffset = 0;&lt;br /&gt; 5int gapEndOffset   = 0;&lt;br /&gt; 6/**//// &lt;summary&gt;&lt;br /&gt; 7/// 小于此长度时增长Buffer/Gap&lt;br /&gt; 8/// &lt;/summary&gt;&lt;br /&gt; 9int minGapLength = 32;&lt;br /&gt;10/**//// &lt;summary&gt;&lt;br /&gt;11/// 每次需要增长时，增长此长度的Gap&lt;br /&gt;12/// &lt;/summary&gt;&lt;br /&gt;13int maxGapLength = 256;&lt;br /&gt;14//重要函数：&lt;br /&gt;15public void SetContent(string text) &lt;br /&gt;16{&lt;br /&gt;17    if (text == null) {&lt;br /&gt;18        text = String.Empty;&lt;br /&gt;19    }&lt;br /&gt;20    buffer = text.ToCharArray();&lt;br /&gt;21    gapBeginOffset = gapEndOffset = 0;&lt;br /&gt;22}&lt;br /&gt;23public void Insert(int offset, string text)&lt;br /&gt;24{&lt;br /&gt;25    Replace(offset, 0, text);&lt;br /&gt;26}&lt;br /&gt;27public void Remove(int offset, int length)&lt;br /&gt;28{&lt;br /&gt;29    Replace(offset, length, String.Empty);&lt;br /&gt;30}&lt;br /&gt;31public void Replace(int offset, int length, string text) &lt;br /&gt;32{&lt;br /&gt;33    if (text == null) {&lt;br /&gt;34        text = String.Empty;&lt;br /&gt;35    }&lt;br /&gt;36    &lt;br /&gt;37    // Math.Max is used so that if we need to resize the array&lt;br /&gt;38    // the new array has enough space for all old chars&lt;br /&gt;39    PlaceGap(offset + length, Math.Max(text.Length - length, 0));&lt;br /&gt;40    text.CopyTo(0, buffer, offset, text.Length);&lt;br /&gt;41    gapBeginOffset += text.Length - length;&lt;br /&gt;42}&lt;br /&gt;43void PlaceGap(int offset, int length) &lt;br /&gt;44{&lt;br /&gt;45    int deltaLength = GapLength - length;&lt;br /&gt;46    // 如果Gap的长度足够大，则只是作移动相关字符的处理&lt;br /&gt;47    if (minGapLength &lt;= deltaLength &amp;&amp; deltaLength &lt;= maxGapLength) {&lt;br /&gt;48        int delta = gapBeginOffset - offset;&lt;br /&gt;49        // check if the gap is already in place&lt;br /&gt;50        if (offset == gapBeginOffset) {&lt;br /&gt;51            return;&lt;br /&gt;52        } else if (offset &lt; gapBeginOffset) {&lt;br /&gt;53            int gapLength = gapEndOffset - gapBeginOffset;&lt;br /&gt;54            Array.Copy(buffer, offset, buffer, offset + gapLength, delta);&lt;br /&gt;55        } else { //offset &gt; gapBeginOffset&lt;br /&gt;56            Array.Copy(buffer, gapEndOffset, buffer, gapBeginOffset, -delta);&lt;br /&gt;57        }&lt;br /&gt;58        gapBeginOffset -= delta;&lt;br /&gt;59        gapEndOffset   -= delta;&lt;br /&gt;60        return;&lt;br /&gt;61    }&lt;br /&gt;62    &lt;br /&gt;63    // 否则，需要新分析buffer的大小，并修改offset等位置数值&lt;br /&gt;64    int oldLength       = GapLength;&lt;br /&gt;65    int newLength       = maxGapLength + length;&lt;br /&gt;66    int newGapEndOffset = offset + newLength;&lt;br /&gt;67    char[] newBuffer    = new char[buffer.Length + newLength - oldLength];    //新分配后将有maxGapLength长度的Gap&lt;br /&gt;68    &lt;br /&gt;69    if (oldLength == 0) {&lt;br /&gt;70        Array.Copy(buffer, 0, newBuffer, 0, offset);&lt;br /&gt;71        Array.Copy(buffer, offset, newBuffer, newGapEndOffset, newBuffer.Length - newGapEndOffset);&lt;br /&gt;72    } else if (offset &lt; gapBeginOffset) {&lt;br /&gt;73        int delta = gapBeginOffset - offset;&lt;br /&gt;74        Array.Copy(buffer, 0, newBuffer, 0, offset);&lt;br /&gt;75        Array.Copy(buffer, offset, newBuffer, newGapEndOffset, delta);&lt;br /&gt;76        Array.Copy(buffer, gapEndOffset, newBuffer, newGapEndOffset + delta, buffer.Length - gapEndOffset);&lt;br /&gt;77    } else {&lt;br /&gt;78        int delta = offset - gapBeginOffset;&lt;br /&gt;79        Array.Copy(buffer, 0, newBuffer, 0, gapBeginOffset);&lt;br /&gt;80        Array.Copy(buffer, gapEndOffset, newBuffer, gapBeginOffset, delta);&lt;br /&gt;81        Array.Copy(buffer, gapEndOffset + delta, newBuffer, newGapEndOffset, newBuffer.Length - newGapEndOffset);&lt;br /&gt;82    }&lt;br /&gt;83    &lt;br /&gt;84    buffer         = newBuffer;&lt;br /&gt;85    gapBeginOffset = offset;&lt;br /&gt;86    gapEndOffset   = newGapEndOffset;&lt;br /&gt;87}&lt;br /&gt;&lt;br /&gt;有了基本的数据容器，核心问题已经解决了，但是在绘制界面时直接使用上面的类，显然不够方便，于是就定义了LineSegment和TextWord类来分别存储行、单词，注意这两个类存储的只是int类型的offset和length信息，而不存储字符或字符串对象。注意TextWord类中有个HighlightColor类型的变量用以存储语法高亮显示信息。&lt;br /&gt;有了上面的这些类，便可以组合起来补充些其它信息对外提供服务了，IDocument接口存在的目的即在于此，它封装了ITextEditorProperties(是否显示空格/Tab/Eol/HRuler等)、UndoStack、ITextBufferStrategy、IHighlightingStrategy、FoldingManager、BookmarkManager等属性对象。&lt;br /&gt;&lt;br /&gt;5、SharpDevelop的SyntaxHighlighting配置文件的定义&lt;br /&gt;是时候对语法高亮显示作一些分析了，此处不详述其实现，而重点分析其配置定义，从中亦可以猜出部分实现。&lt;br /&gt;相关配置文件均保存在ICSharpCode.TextEditor项目\Resource\目录下&lt;br /&gt;首先SyntaxMode.xml文件中显示了已定义的文件类型及其声明文件位置，其解析类参见\src\Document\HighlightingStrategy\SyntaxModes\FileSyntaxModeProvider.cs&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;SyntaxMode.xml&lt;br /&gt; 1&lt;SyntaxModes version="1.0"&gt;&lt;br /&gt; 2    &lt;Mode file       = "ASPX.xshd"&lt;br /&gt; 3          name       = "ASP/XHTML"&lt;br /&gt; 4          extensions = ".asp;.aspx;.asax;.asmx"/&gt;&lt;br /&gt; 5    &lt;br /&gt; 6    &lt;Mode file       = "BAT-Mode.xshd"&lt;br /&gt; 7          name       = "BAT"&lt;br /&gt; 8          extensions = ".bat"/&gt;&lt;br /&gt; 9    &lt;br /&gt;10    &lt;Mode file       = "CPP-Mode.xshd"&lt;br /&gt;11          name       = "C++.NET"&lt;br /&gt;12          extensions = ".c;.h;.cc;.C;.cpp;.hpp"/&gt;&lt;br /&gt;13    &lt;br /&gt;14    &lt;Mode file       = "CSharp-Mode.xshd"&lt;br /&gt;15          name       = "C#"&lt;br /&gt;16          extensions = ".cs"/&gt;&lt;br /&gt;17    &lt;br /&gt;18    &lt;Mode file       = "XML-Mode.xshd"&lt;br /&gt;19          name       = "XML"&lt;br /&gt;20          extensions = ".xml;.xsl;.xslt;.xsd;.manifest;.config;.addin;.xshd; .wxs;.proj;.csproj;.vbproj;.ilproj;.booproj;.build;.xfrm;.targets; .xaml;.xpt;.xft;.map;.wsdl;.disco"/&gt;&lt;br /&gt;21&lt;/SyntaxModes&gt;&lt;br /&gt;取CSharp-Mode.xshd(注：xshd是Xml Syntax Highlighting Definition的缩写)为例，查看其定义：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;CSharp-Mode.xshd&lt;br /&gt; 1&lt;?xml version="1.0"?&gt;&lt;br /&gt; 2&lt;SyntaxDefinition name = "C#" extensions = ".cs"&gt;&lt;br /&gt; 3    &lt;Properties&gt;&lt;br /&gt; 4        &lt;Property name="LineComment" value="//"/&gt;&lt;br /&gt; 5    &lt;/Properties&gt;&lt;br /&gt; 6    &lt;Digits name = "Digits" bold = "false" italic = "false" color = "DarkBlue"/&gt;&lt;br /&gt; 7    &lt;RuleSets&gt;&lt;br /&gt; 8        &lt;RuleSet ignorecase="false"&gt;&lt;br /&gt; 9            &lt;Delimiters&gt;&amp;amp;&amp;lt;&amp;gt;~!%^*()-+=|\#/{}[]:;"' ,    .?&lt;/Delimiters&gt;&lt;br /&gt;10            &lt;Span name = "PreprocessorDirectives" rule = "PreprocessorSet" bold="false" italic="false" color="Green" stopateol = "true"&gt;&lt;br /&gt;11                &lt;Begin&gt;#&lt;/Begin&gt;&lt;br /&gt;12            &lt;/Span&gt;&lt;br /&gt;13            &lt;Span name = "BlockComment" rule = "CommentMarkerSet" bold = "false" italic = "false" color = "Green" stopateol = "false"&gt;&lt;br /&gt;14                &lt;Begin&gt;/*&lt;/Begin&gt;&lt;br /&gt;15                &lt;End&gt;*/&lt;/End&gt;&lt;br /&gt;16            &lt;/Span&gt;&lt;br /&gt;17            &lt;KeyWords name = "Punctuation" bold = "false" italic = "false" color = "DarkGreen"&gt;&lt;br /&gt;18                &lt;Key word = "?" /&gt;&lt;br /&gt;19                &lt;Key word = "," /&gt;&lt;br /&gt;20                &lt;Key word = "." /&gt;&lt;br /&gt;21                &lt;Key word = ";" /&gt;&lt;br /&gt;22                &lt;Key word = "(" /&gt;&lt;br /&gt;23                &lt;Key word = ")" /&gt;&lt;br /&gt;24                &lt;Key word = "[" /&gt;&lt;br /&gt;25                &lt;Key word = "]" /&gt;&lt;br /&gt;26                &lt;Key word = "{" /&gt;&lt;br /&gt;27                &lt;Key word = "}" /&gt;&lt;br /&gt;28                &lt;Key word = "+" /&gt;&lt;br /&gt;29                &lt;Key word = "-" /&gt;&lt;br /&gt;30                &lt;Key word = "/" /&gt;&lt;br /&gt;31                &lt;Key word = "%" /&gt;&lt;br /&gt;32                &lt;Key word = "*" /&gt;&lt;br /&gt;33                &lt;Key word = "&amp;lt;" /&gt;&lt;br /&gt;34                &lt;Key word = "&amp;gt;" /&gt;&lt;br /&gt;35                &lt;Key word = "^" /&gt;&lt;br /&gt;36                &lt;Key word = "=" /&gt;&lt;br /&gt;37                &lt;Key word = "~" /&gt;&lt;br /&gt;38                &lt;Key word = "!" /&gt;&lt;br /&gt;39                &lt;Key word = "|" /&gt;&lt;br /&gt;40                &lt;Key word = "&amp;amp;" /&gt;&lt;br /&gt;41              &lt;/KeyWords&gt;&lt;br /&gt;42          &lt;br /&gt;43            &lt;KeyWords name = "AccessKeywords" bold="true" italic="false" color="Black"&gt;&lt;br /&gt;44                &lt;Key word = "this" /&gt;&lt;br /&gt;45                &lt;Key word = "base" /&gt;&lt;br /&gt;46            &lt;/KeyWords&gt;&lt;br /&gt;47            &lt;br /&gt;48            &lt;KeyWords name = "OperatorKeywords" bold="true" italic="false" color="DarkCyan"&gt;&lt;br /&gt;49                &lt;Key word = "as" /&gt;&lt;br /&gt;50                &lt;Key word = "is" /&gt;&lt;br /&gt;51                &lt;Key word = "new" /&gt;&lt;br /&gt;52                &lt;Key word = "sizeof" /&gt;&lt;br /&gt;53                &lt;Key word = "typeof" /&gt;&lt;br /&gt;54                &lt;Key word = "true" /&gt;&lt;br /&gt;55                &lt;Key word = "false" /&gt;&lt;br /&gt;56                &lt;Key word = "stackalloc" /&gt;&lt;br /&gt;57            &lt;/KeyWords&gt;&lt;br /&gt;58        &lt;/RuleSet&gt;&lt;br /&gt;59    &lt;/RuleSets&gt;&lt;br /&gt;60&lt;/SyntaxDefinition&gt;&lt;br /&gt;上面的文件公摘选了部分标签，其中&lt;br /&gt;&lt;Property&gt;标签定义了指定名称属性的指定值&lt;br /&gt;&lt;Digits&gt;标签定义了数值的字体显示样式&lt;br /&gt;&lt;Delimiters&gt;定义了分隔单词的字符&lt;br /&gt;&lt;Span&gt;定义了包含在此指定Begin/End中的字符的显示样式,注意没有&lt;End&gt;标签的一般设stopateol(stop at end-of-line)为true&lt;br /&gt;&lt;KeyWords&gt;指定了其子集&lt;Key&gt;声明的单词的显示样式&lt;br /&gt;&lt;br /&gt;6、SharpDevelop的TextEditor控件的实现概述&lt;br /&gt;接下来的任务是要显示和支持用户输入了，直接使用TextBox或RichTextBox好像都不太现实，效率上也必定有不少损失，于是SharpDevelop的方式是直接继承自Control, Panel, UserControl 的方式来实现编辑控件(参见ICSharpCode.TextEditor项目\src\Gui\...)。&lt;br /&gt;首先使用TextEditorControlBase(继承自UserControl)封装当前文件路径、Encoding、IDocument对象、ITextEditorProperties对象、快捷键列表(Dictionary&lt;Keys, IEditAction&gt;类型)的变量，提供LoadFile()、SaveFile()等重要方法。&lt;br /&gt;TextEditorControl类继承自上面的类，并声明了Panel、Splitter、TextAreaControl、PrintDocument控件，其中显示文件的核心控件是TextAreaControl,该控件在此类中被声明了两个变量，默认只有一个primaryTextArea显示，支持切分为两个窗口的显示，当有两个窗口时，Splitter控件才有效；PrinDocument控件用以打印输出内容；该类的另一个重要功能是提供了UnDo()、Redo()方法。&lt;br /&gt;TextAreaControl(继承自Panel)控件，封装了TextArea、VScrollBar、HScrollBar控件，其中TextArea负责文件数据显示，另外两个控件负责文件内容大于可见尺寸时的滚动条服务。&lt;br /&gt;TextArea(继承自Control)封装了TextView, IconBarMargin, GutterMargin, FoldMargin, SelectionManager, Caret 等控件或类对象，其中前四个控件均继承自AbstractMargin，代表区域对象，各自负责字符区域(较大的文件内容绘制区)、图标区域(如Bookmark图标所在列)、Gutter区域(如行号)、折叠控制区域的绘制，SelectionManager用以控制选中项，Caret用以控制光标位置调整和显示。&lt;br /&gt;&lt;br /&gt;下面是一些我在读代码的过程中有过的疑问及解答：&lt;br /&gt;a, 加载文件时发生了什么？&lt;br /&gt;答：加载文件时控件根据文件的后缀名选择了相应的高亮显示策略，然后读取文件的内容并生成相应的GapTextBufferStrategy, LineSegment, TextWord 等对象，并且对所有的TextWord对象的HighlightColor类型成员变量完成分析赋值(用以在Paint函数中显示)，相关代码如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;LoadFile()相关代码&lt;br /&gt; 1//取自TextEditorControlBase.cs&lt;br /&gt; 2public void LoadFile(string fileName, bool autoLoadHighlighting, bool autodetectEncoding)&lt;br /&gt; 3{&lt;br /&gt; 4    BeginUpdate();&lt;br /&gt; 5    document.TextContent = String.Empty;&lt;br /&gt; 6    document.UndoStack.ClearAll();&lt;br /&gt; 7    document.BookmarkManager.Clear();&lt;br /&gt; 8    if (autoLoadHighlighting) {&lt;br /&gt; 9                //根据文件扩展名判断并赋值高亮显示的策略&lt;br /&gt;10        document.HighlightingStrategy = HighlightingStrategyFactory.CreateHighlightingStrategyForFile(fileName);&lt;br /&gt;11    }&lt;br /&gt;12    &lt;br /&gt;13    if (autodetectEncoding) {&lt;br /&gt;14        Encoding encoding = this.Encoding;&lt;br /&gt;15                //赋值&lt;br /&gt;16        Document.TextContent = Util.FileReader.ReadFileContent(fileName, ref encoding, this.TextEditorProperties.Encoding);&lt;br /&gt;17        this.Encoding = encoding;&lt;br /&gt;18    } else {&lt;br /&gt;19        using (StreamReader reader = new StreamReader(fileName, this.Encoding)) {&lt;br /&gt;20            Document.TextContent = reader.ReadToEnd();&lt;br /&gt;21        }&lt;br /&gt;22    }&lt;br /&gt;23    &lt;br /&gt;24    this.FileName = fileName;&lt;br /&gt;25    OptionsChanged();&lt;br /&gt;26    Document.UpdateQueue.Clear();&lt;br /&gt;27    EndUpdate();&lt;br /&gt;28    &lt;br /&gt;29    Refresh();&lt;br /&gt;30}&lt;br /&gt;31//引自DefaultDocument.cs&lt;br /&gt;32ITextBufferStrategy   textBufferStrategy   = null;&lt;br /&gt;33ILineManager          lineTrackingStrategy = null;&lt;br /&gt;34public string TextContent {&lt;br /&gt;35    get {&lt;br /&gt;36        return GetText(0, textBufferStrategy.Length);&lt;br /&gt;37    }&lt;br /&gt;38    set {&lt;br /&gt;39        Debug.Assert(textBufferStrategy != null);&lt;br /&gt;40        Debug.Assert(lineTrackingStrategy != null);&lt;br /&gt;41        OnDocumentAboutToBeChanged(new DocumentEventArgs(this, 0, 0, value));&lt;br /&gt;42                //赋值&lt;br /&gt;43        textBufferStrategy.SetContent(value);&lt;br /&gt;44                //赋值 &amp;&amp; 分析并完成高亮分析的赋值&lt;br /&gt;45        lineTrackingStrategy.SetContent(value);&lt;br /&gt;46        &lt;br /&gt;47        OnDocumentChanged(new DocumentEventArgs(this, 0, 0, value));&lt;br /&gt;48        OnTextContentChanged(EventArgs.Empty);&lt;br /&gt;49    }&lt;br /&gt;50}&lt;br /&gt;51//引自DefaultLineManager.cs&lt;br /&gt;52public void SetContent(string text)&lt;br /&gt;53{&lt;br /&gt;54    lineCollection.Clear();&lt;br /&gt;55    if (text != null) {&lt;br /&gt;56        textLength = text.Length;&lt;br /&gt;57                // 生成LineSegment集合&lt;br /&gt;58        CreateLines(text, 0, 0);&lt;br /&gt;59                // 高亮分析&lt;br /&gt;60        RunHighlighter();&lt;br /&gt;61    }&lt;br /&gt;62}&lt;br /&gt;b, 控件如何响应键盘事件？&lt;br /&gt;答：对于方向键及快捷功能键通过预定义的实现IEditAction接口的类响应(执行功能，不影响字符内容)；其它字母/数字键直接输入，同时执行更新Folding, Bookmark, Higlighting等属性信息。相关代码：&lt;br /&gt;键盘事件响应&lt;br /&gt;  1//功能键的定义(引自TextEditorControlBase.cs)：&lt;br /&gt;  2protected Dictionary&lt;Keys, IEditAction&gt; editactions = new Dictionary&lt;Keys, IEditAction&gt;();&lt;br /&gt;  3protected TextEditorControlBase()&lt;br /&gt;  4{&lt;br /&gt;  5    GenerateDefaultActions();&lt;br /&gt;  6    HighlightingManager.Manager.ReloadSyntaxHighlighting += new EventHandler(ReloadHighlighting);&lt;br /&gt;  7}&lt;br /&gt;  8void GenerateDefaultActions()&lt;br /&gt;  9{&lt;br /&gt; 10    editactions[Keys.Left] = new CaretLeft();&lt;br /&gt; 11    editactions[Keys.Left | Keys.Shift] = new ShiftCaretLeft();&lt;br /&gt; 12    editactions[Keys.Left | Keys.Control] = new WordLeft();&lt;br /&gt; 13    editactions[Keys.Left | Keys.Control | Keys.Shift] = new ShiftWordLeft();&lt;br /&gt; 14    editactions[Keys.Right] = new CaretRight();&lt;br /&gt; 15    editactions[Keys.Right | Keys.Shift] = new ShiftCaretRight();&lt;br /&gt; 16    editactions[Keys.Right | Keys.Control] = new WordRight();&lt;br /&gt; 17    editactions[Keys.Right | Keys.Control | Keys.Shift] = new ShiftWordRight();&lt;br /&gt; 18    editactions[Keys.Up] = new CaretUp();&lt;br /&gt; 19    editactions[Keys.Up | Keys.Shift] = new ShiftCaretUp();&lt;br /&gt; 20    editactions[Keys.Up | Keys.Control] = new ScrollLineUp();&lt;br /&gt; 21    editactions[Keys.Down] = new CaretDown();&lt;br /&gt; 22    editactions[Keys.Down | Keys.Shift] = new ShiftCaretDown();&lt;br /&gt; 23    editactions[Keys.Down | Keys.Control] = new ScrollLineDown();&lt;br /&gt; 24    &lt;br /&gt; 25    editactions[Keys.Insert] = new ToggleEditMode();&lt;br /&gt; 26    editactions[Keys.Insert | Keys.Control] = new Copy();&lt;br /&gt; 27    editactions[Keys.Insert | Keys.Shift] = new Paste();&lt;br /&gt; 28    editactions[Keys.Delete] = new Delete();&lt;br /&gt; 29    editactions[Keys.Delete | Keys.Shift] = new Cut();&lt;br /&gt; 30    editactions[Keys.Home] = new Home();&lt;br /&gt; 31    editactions[Keys.Home | Keys.Shift] = new ShiftHome();&lt;br /&gt; 32    editactions[Keys.Home | Keys.Control] = new MoveToStart();&lt;br /&gt; 33    editactions[Keys.Home | Keys.Control | Keys.Shift] = new ShiftMoveToStart();&lt;br /&gt; 34    editactions[Keys.End] = new End();&lt;br /&gt; 35    editactions[Keys.End | Keys.Shift] = new ShiftEnd();&lt;br /&gt; 36    editactions[Keys.End | Keys.Control] = new MoveToEnd();&lt;br /&gt; 37    editactions[Keys.End | Keys.Control | Keys.Shift] = new ShiftMoveToEnd();&lt;br /&gt; 38    editactions[Keys.PageUp] = new MovePageUp();&lt;br /&gt; 39    editactions[Keys.PageUp | Keys.Shift] = new ShiftMovePageUp();&lt;br /&gt; 40    editactions[Keys.PageDown] = new MovePageDown();&lt;br /&gt; 41    editactions[Keys.PageDown | Keys.Shift] = new ShiftMovePageDown();&lt;br /&gt; 42    &lt;br /&gt; 43    editactions[Keys.Return] = new Return();&lt;br /&gt; 44    editactions[Keys.Tab] = new Tab();&lt;br /&gt; 45    editactions[Keys.Tab | Keys.Shift] = new ShiftTab();&lt;br /&gt; 46    editactions[Keys.Back] = new Backspace();&lt;br /&gt; 47    editactions[Keys.Back | Keys.Shift] = new Backspace();&lt;br /&gt; 48    &lt;br /&gt; 49    editactions[Keys.X | Keys.Control] = new Cut();&lt;br /&gt; 50    editactions[Keys.C | Keys.Control] = new Copy();&lt;br /&gt; 51    editactions[Keys.V | Keys.Control] = new Paste();&lt;br /&gt; 52    &lt;br /&gt; 53    editactions[Keys.A | Keys.Control] = new SelectWholeDocument();&lt;br /&gt; 54    editactions[Keys.Escape] = new ClearAllSelections();&lt;br /&gt; 55    &lt;br /&gt; 56    editactions[Keys.Divide | Keys.Control] = new ToggleComment();&lt;br /&gt; 57    editactions[Keys.OemQuestion | Keys.Control] = new ToggleComment();&lt;br /&gt; 58    &lt;br /&gt; 59    editactions[Keys.Back | Keys.Alt]  = new Actions.Undo();&lt;br /&gt; 60    editactions[Keys.Z | Keys.Control] = new Actions.Undo();&lt;br /&gt; 61    editactions[Keys.Y | Keys.Control] = new Redo();&lt;br /&gt; 62    &lt;br /&gt; 63    editactions[Keys.Delete | Keys.Control] = new DeleteWord();&lt;br /&gt; 64    editactions[Keys.Back | Keys.Control]   = new WordBackspace();&lt;br /&gt; 65    editactions[Keys.D | Keys.Control]      = new DeleteLine();&lt;br /&gt; 66    editactions[Keys.D | Keys.Shift | Keys.Control]      = new DeleteToLineEnd();&lt;br /&gt; 67    &lt;br /&gt; 68    editactions[Keys.B | Keys.Control]      = new GotoMatchingBrace();&lt;br /&gt; 69}&lt;br /&gt; 70internal IEditAction GetEditAction(Keys keyData)&lt;br /&gt; 71{&lt;br /&gt; 72    if (!editactions.ContainsKey(keyData)) {&lt;br /&gt; 73        return null;&lt;br /&gt; 74    }&lt;br /&gt; 75    return (IEditAction)editactions[keyData];&lt;br /&gt; 76}&lt;br /&gt; 77//功能键的响应(取自TextArea.cs)：&lt;br /&gt; 78protected override bool ProcessDialogKey(Keys keyData)&lt;br /&gt; 79{&lt;br /&gt; 80    return ExecuteDialogKey(keyData) || base.ProcessDialogKey(keyData);&lt;br /&gt; 81}&lt;br /&gt; 82public bool ExecuteDialogKey(Keys keyData)&lt;br /&gt; 83{&lt;br /&gt; 84    // try, if a dialog key processor was set to use this&lt;br /&gt; 85    if (DoProcessDialogKey != null &amp;&amp; DoProcessDialogKey(keyData)) {&lt;br /&gt; 86        return true;&lt;br /&gt; 87    }&lt;br /&gt; 88    &lt;br /&gt; 89    if (keyData == Keys.Back || keyData == Keys.Delete || keyData == Keys.Enter) {&lt;br /&gt; 90        if (TextEditorProperties.UseCustomLine == true) {&lt;br /&gt; 91            if (SelectionManager.HasSomethingSelected) {&lt;br /&gt; 92                if (Document.CustomLineManager.IsReadOnly(SelectionManager.SelectionCollection[0], false))&lt;br /&gt; 93                    return true;&lt;br /&gt; 94            } else {&lt;br /&gt; 95                int curLineNr   = Document.GetLineNumberForOffset(Caret.Offset);&lt;br /&gt; 96                if (Document.CustomLineManager.IsReadOnly(curLineNr, false) == true)&lt;br /&gt; 97                    return true;&lt;br /&gt; 98                if ((Caret.Column == 0) &amp;&amp; (curLineNr - 1 &gt;= 0) &amp;&amp; keyData == Keys.Back &amp;&amp;&lt;br /&gt; 99                    Document.CustomLineManager.IsReadOnly(curLineNr - 1, false) == true)&lt;br /&gt;100                    return true;&lt;br /&gt;101                if (keyData == Keys.Delete) {&lt;br /&gt;102                    LineSegment curLine = Document.GetLineSegment(curLineNr);&lt;br /&gt;103                    if (curLine.Offset + curLine.Length == Caret.Offset &amp;&amp;&lt;br /&gt;104                        Document.CustomLineManager.IsReadOnly(curLineNr + 1, false) == true) {&lt;br /&gt;105                        return true;&lt;br /&gt;106                    }&lt;br /&gt;107                }&lt;br /&gt;108            }&lt;br /&gt;109        }&lt;br /&gt;110    }&lt;br /&gt;111    &lt;br /&gt;112    // if not (or the process was 'silent', use the standard edit actions&lt;br /&gt;113    IEditAction action =  motherTextEditorControl.GetEditAction(keyData);&lt;br /&gt;114    AutoClearSelection = true;&lt;br /&gt;115    if (action != null) {&lt;br /&gt;116        motherTextEditorControl.BeginUpdate();&lt;br /&gt;117        try {&lt;br /&gt;118            lock (Document) {&lt;br /&gt;119                                // 执行相关的功能操作&lt;br /&gt;120                action.Execute(this);&lt;br /&gt;121                if (SelectionManager.HasSomethingSelected &amp;&amp; AutoClearSelection /**//*&amp;&amp; caretchanged*/) {&lt;br /&gt;122                    if (Document.TextEditorProperties.DocumentSelectionMode == DocumentSelectionMode.Normal) {&lt;br /&gt;123                        SelectionManager.ClearSelection();&lt;br /&gt;124                    }&lt;br /&gt;125                }&lt;br /&gt;126            }&lt;br /&gt;127        } finally {&lt;br /&gt;128            motherTextEditorControl.EndUpdate();&lt;br /&gt;129            Caret.UpdateCaretPosition();&lt;br /&gt;130        }&lt;br /&gt;131        return true;&lt;br /&gt;132    }&lt;br /&gt;133    return false;&lt;br /&gt;134}&lt;br /&gt;135&lt;br /&gt;136//输入键的响应(取自TextArea.cs)：&lt;br /&gt;137protected override void OnKeyPress(KeyPressEventArgs e)&lt;br /&gt;138{&lt;br /&gt;139    base.OnKeyPress(e);&lt;br /&gt;140    SimulateKeyPress(e.KeyChar);&lt;br /&gt;141    e.Handled = true;&lt;br /&gt;142}&lt;br /&gt;143public void SimulateKeyPress(char ch)&lt;br /&gt;144{&lt;br /&gt;145    if (Document.ReadOnly) {&lt;br /&gt;146        return;&lt;br /&gt;147    }&lt;br /&gt;148    &lt;br /&gt;149    if (TextEditorProperties.UseCustomLine == true) {&lt;br /&gt;150        if (SelectionManager.HasSomethingSelected) {&lt;br /&gt;151            if (Document.CustomLineManager.IsReadOnly(SelectionManager.SelectionCollection[0], false))&lt;br /&gt;152                return;&lt;br /&gt;153        } else if (Document.CustomLineManager.IsReadOnly(Caret.Line, false) == true)&lt;br /&gt;154            return;&lt;br /&gt;155    }&lt;br /&gt;156    &lt;br /&gt;157    if (ch &lt; ' ') {&lt;br /&gt;158        return;&lt;br /&gt;159    }&lt;br /&gt;160    &lt;br /&gt;161    if (!HiddenMouseCursor &amp;&amp; TextEditorProperties.HideMouseCursor) {&lt;br /&gt;162        HiddenMouseCursor = true;&lt;br /&gt;163        Cursor.Hide();&lt;br /&gt;164    }&lt;br /&gt;165    CloseToolTip();&lt;br /&gt;166    &lt;br /&gt;167    motherTextEditorControl.BeginUpdate();&lt;br /&gt;168    // INSERT char&lt;br /&gt;169    if (!HandleKeyPress(ch)) {&lt;br /&gt;170        switch (Caret.CaretMode) {&lt;br /&gt;171            case CaretMode.InsertMode:&lt;br /&gt;172                InsertChar(ch);&lt;br /&gt;173                break;&lt;br /&gt;174            case CaretMode.OverwriteMode:&lt;br /&gt;175                ReplaceChar(ch);&lt;br /&gt;176                break;&lt;br /&gt;177            default:&lt;br /&gt;178                Debug.Assert(false, "Unknown caret mode " + Caret.CaretMode);&lt;br /&gt;179                break;&lt;br /&gt;180        }&lt;br /&gt;181    }&lt;br /&gt;182    &lt;br /&gt;183    int currentLineNr = Caret.Line;&lt;br /&gt;184    int delta = Document.FormattingStrategy.FormatLine(this, currentLineNr, Document.PositionToOffset(Caret.Position), ch);&lt;br /&gt;185    &lt;br /&gt;186    motherTextEditorControl.EndUpdate();&lt;br /&gt;187    if (delta != 0) {&lt;br /&gt;188//                this.motherTextEditorControl.UpdateLines(currentLineNr, currentLineNr);&lt;br /&gt;189    }&lt;br /&gt;190}&lt;br /&gt;191//输入键通过底层的方法输入字符和更改高亮显示，如下分析(以Insert为例，取自DefaultDocument.cs)：&lt;br /&gt;192public void Insert(int offset, string text)&lt;br /&gt;193{&lt;br /&gt;194    if (readOnly) {&lt;br /&gt;195        return;&lt;br /&gt;196    }&lt;br /&gt;197    OnDocumentAboutToBeChanged(new DocumentEventArgs(this, offset, -1, text));&lt;br /&gt;198    DateTime time = DateTime.Now;&lt;br /&gt;199    //增加字符&lt;br /&gt;200    textBufferStrategy.Insert(offset, text);&lt;br /&gt;201    &lt;br /&gt;202    time = DateTime.Now;&lt;br /&gt;203    //更新LineSegment, TextWord对象&lt;br /&gt;204    lineTrackingStrategy.Insert(offset, text);&lt;br /&gt;205    &lt;br /&gt;206    time = DateTime.Now;&lt;br /&gt;207    &lt;br /&gt;208    undoStack.Push(new UndoableInsert(this, offset, text));&lt;br /&gt;209    &lt;br /&gt;210    time = DateTime.Now;&lt;br /&gt;211    OnDocumentChanged(new DocumentEventArgs(this, offset, -1, text));&lt;br /&gt;212}&lt;br /&gt;213// 追踪到DefaultLineManager.cs中Insert()方法实际上调用到Replace(offset,length,string.Empty)方法：&lt;br /&gt;214public void Replace(int offset, int length, string text) &lt;br /&gt;215{&lt;br /&gt;216    int lineNumber = GetLineNumberForOffset(offset);            &lt;br /&gt;217    int insertLineNumber = lineNumber;&lt;br /&gt;218    if (Remove(lineNumber, offset, length)) {&lt;br /&gt;219        --lineNumber;&lt;br /&gt;220    }&lt;br /&gt;221    &lt;br /&gt;222    lineNumber += Insert(insertLineNumber, offset, text);&lt;br /&gt;223    &lt;br /&gt;224    int delta = -length;&lt;br /&gt;225    if (text != null) {&lt;br /&gt;226        delta = text.Length + delta;&lt;br /&gt;227    }&lt;br /&gt;228    &lt;br /&gt;229    if (delta != 0) {&lt;br /&gt;230        AdaptLineOffsets(lineNumber, delta);        &lt;br /&gt;231    }&lt;br /&gt;232    //启用高亮显示分析 -----   注：此时的 markLines 仅存储变化的相关行，而SetContent时存储的是所有行，因此只是按需分析&lt;br /&gt;233    RunHighlighter();&lt;br /&gt;234}&lt;br /&gt;c, 文件字符的绘制究竟是在何处？&lt;br /&gt;答：在TextView.cs中的public override void Paint(Graphics g, Rectangle rect)函数中，重要函数：PaintLinePart()，辅助绘制函数：DrawDocumentWord(), DrawBracketHighlight(), DrawSpaceMarker(), DrawVerticalRuler() 等&lt;br /&gt;&lt;br /&gt;d, 括号匹配在何处被定义和捕捉更新？&lt;br /&gt;答：TextArea.cs中的List&lt;BracketHighlightingSheme&gt; bracketshemes  = new List&lt;BracketHighlightingSheme&gt;();变量存储在查找的匹配项，SearchMatchingBracket()方法中搜索并更新匹配项的显示，相关代码如下：&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;括号匹配&lt;br /&gt; 1//引自TextArea.cs&lt;br /&gt; 2List&lt;BracketHighlightingSheme&gt; bracketshemes  = new List&lt;BracketHighlightingSheme&gt;();&lt;br /&gt; 3Caret            caret;&lt;br /&gt; 4public TextArea(TextEditorControl motherTextEditorControl, TextAreaControl motherTextAreaControl)&lt;br /&gt; 5{&lt;br /&gt; 6    // 省略无关代码&lt;br /&gt; 7    bracketshemes.Add(new BracketHighlightingSheme('{', '}'));&lt;br /&gt; 8    bracketshemes.Add(new BracketHighlightingSheme('(', ')'));&lt;br /&gt; 9    bracketshemes.Add(new BracketHighlightingSheme('[', ']'));&lt;br /&gt;10    &lt;br /&gt;11    caret.PositionChanged += new EventHandler(SearchMatchingBracket);&lt;br /&gt;12    // 省略无关代码&lt;br /&gt;13}&lt;br /&gt;14void SearchMatchingBracket(object sender, EventArgs e)&lt;br /&gt;15{&lt;br /&gt;16    if (!TextEditorProperties.ShowMatchingBracket) {&lt;br /&gt;17        textView.Highlight = null;&lt;br /&gt;18        return;&lt;br /&gt;19    }&lt;br /&gt;20    bool changed = false;&lt;br /&gt;21    if (caret.Offset == 0) {&lt;br /&gt;22        if (textView.Highlight != null) {&lt;br /&gt;23            int line  = textView.Highlight.OpenBrace.Y;&lt;br /&gt;24            int line2 = textView.Highlight.CloseBrace.Y;&lt;br /&gt;25            textView.Highlight = null;&lt;br /&gt;26            UpdateLine(line);&lt;br /&gt;27            UpdateLine(line2);&lt;br /&gt;28        }&lt;br /&gt;29        return;&lt;br /&gt;30    }&lt;br /&gt;31    foreach (BracketHighlightingSheme bracketsheme in bracketshemes) {&lt;br /&gt;32//                if (bracketsheme.IsInside(textareapainter.Document, textareapainter.Document.Caret.Offset)) {&lt;br /&gt;33        Highlight highlight = bracketsheme.GetHighlight(Document, Caret.Offset - 1);&lt;br /&gt;34        if (textView.Highlight != null &amp;&amp; textView.Highlight.OpenBrace.Y &gt;=0 &amp;&amp; textView.Highlight.OpenBrace.Y &lt; Document.TotalNumberOfLines) {&lt;br /&gt;35            //取消旧匹配项的高亮显示&lt;br /&gt;36            UpdateLine(textView.Highlight.OpenBrace.Y);&lt;br /&gt;37        }&lt;br /&gt;38        if (textView.Highlight != null &amp;&amp; textView.Highlight.CloseBrace.Y &gt;=0 &amp;&amp; textView.Highlight.CloseBrace.Y &lt; Document.TotalNumberOfLines) {&lt;br /&gt;39            //取消旧匹配项的高亮显示&lt;br /&gt;40            UpdateLine(textView.Highlight.CloseBrace.Y);&lt;br /&gt;41        }&lt;br /&gt;42        textView.Highlight = highlight;&lt;br /&gt;43        if (highlight != null) {&lt;br /&gt;44            changed = true;&lt;br /&gt;45            break;&lt;br /&gt;46        }&lt;br /&gt;47//                }&lt;br /&gt;48    }&lt;br /&gt;49    if (changed || textView.Highlight != null) {&lt;br /&gt;50        int line = textView.Highlight.OpenBrace.Y;&lt;br /&gt;51        int line2 = textView.Highlight.CloseBrace.Y;&lt;br /&gt;52        if (!changed) {&lt;br /&gt;53            textView.Highlight = null;&lt;br /&gt;54        }&lt;br /&gt;55        //更新显示新匹配项 OpenBrace&lt;br /&gt;56        UpdateLine(line);&lt;br /&gt;57        //更新显示新匹配项 CloseBrace&lt;br /&gt;58        UpdateLine(line2);&lt;br /&gt;59    }&lt;br /&gt;60}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;7、待分析的部分&lt;br /&gt;本篇讨论暂未涉及如下(有价值?)内容的分析：&lt;br /&gt;SyntaxHighlighting实现分析&lt;br /&gt;BookmarkManager, FoldingManager, FormattingManager等&lt;br /&gt;Paint()处理中坐标分析及转换&lt;br /&gt;&lt;br /&gt;8、总结&lt;br /&gt;本篇分析对应的《Dissecting a C# Application Inside SharpDevelop》书中的章节：&lt;br /&gt;Chapter 7: Internationalization&lt;br /&gt;Chapter 8: Document Management&lt;br /&gt;Chapter 9: Syntax Highlighting&lt;br /&gt;Chapter 11: Writing the Editor Control&lt;br /&gt;&lt;br /&gt;对于该Demo中尚未实现的代码折叠、字符串的查找/替换功能将在下个礼拜读了10,12,13,14章后作进一步分析&lt;br /&gt;&lt;br /&gt;SharpDevelop浅析_4_TextEditor_自动完成、代码折叠……&lt;br /&gt;&lt;br /&gt;Parser及其应用: Code Completion, Method Insight, Class Scout ...&lt;br /&gt;&lt;br /&gt;可见新增功能如下(仅支持.cs文件)：&lt;br /&gt;a, 鼠标停留在方法、属性等位置时，会显示出相关的文档描述tooltip&lt;br /&gt;b, 输入时支持自动完成&lt;br /&gt;c, 编辑窗口顶部有类列表和成员(方法、变量等)列表下拉框用以快速浏览、定位&lt;br /&gt;d, 编辑窗口左侧有折叠线用以方法、类等的代码折叠&lt;br /&gt;相应的Demo工程中新增项目如下：&lt;br /&gt;a, SharpEditor:   包含扩展TextEditor的控件, Dom结构, ParserService， 自动完成功能代码等&lt;br /&gt;b, NRefactor :    代码解析功能&lt;br /&gt;c, CSharpBinding: 对应 .cs 文件的具体实现支持&lt;br /&gt;&lt;br /&gt;[题外话]: &lt;br /&gt;关于代码解析(Parser)相关的代码，我没看懂，所以在这里只说个大概，更多地谈谈Parser的使用；抛砖引玉，希望有相关经验的网友提供详尽的分析。&lt;br /&gt;前两周工作上的项目实施，每天都搞得比较累，所以这篇文章到现在才写了出来，明天是大年三十了，这个系列的文章也只剩下一篇Windows Form Designer，只能等过了年再放上来喽。&lt;br /&gt;另外，这个系列写完后，暂不打算深究一些没明白的细节，接下来想看下os workflow 或 CommunityServer...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2、Parser实现概述&lt;br /&gt;(1)首先，SharpEditor项目中的Dom下定义了以下重要类：&lt;br /&gt;a, IDecoration及其子类:   代码表现的辅助对象，如IClass, IMethod, IProperty等&lt;br /&gt;b, ResolveResult及其子类: 分析结果对象，如MethodResolveResult, TypeResolveResult等&lt;br /&gt;c, 其它重要类：           IExpressionFinder, IParser, IResolve, ICompilationUnit 等&lt;br /&gt;&lt;br /&gt;(2)重要服务类：&lt;br /&gt;ParserService:   提供 GetExpressionFinder(), Resolve(), ParseFile()等重要方法，相关重要类: ProjectContentRegistry, DefaultProjectContent, ReflectionProjectContent等&lt;br /&gt;AmbienceService: 提供 IAmbience的实现类用以将分析结果转换为相应的字符描述&lt;br /&gt;&lt;br /&gt;(3)Parser分析步骤：&lt;br /&gt;以鼠标悬浮的Tooltip显示为例：DebuggerService根据文件类型返回对应的IExpressionFinder实现类，再根据鼠标位置找到并返回ExpressionResult对象，然后找到适当的IResolver实现类调用Resolve()方法返回结果ResolveResult对象，最后由相应的IAmbience实现类转换成结果字符，并调用e.ShowToolTip(toolTipText);显示。&lt;br /&gt;&lt;br /&gt;(4)对于.NET默认类库的分析转换：&lt;br /&gt;默认引进的命名空间的类结构和文档说明一般可以在"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\"目录下找到(如System.dll和System.xml)，但是如果每次都要重新分析dll代码结构和xml注释显然是比较花费时间的，于是SharpDevelop采用的方式是将分析过的数据(Dom下的类结构表示数据?，二进制的.dat文件)存储到"C:\Documents and Settings\michael\Local Settings\Temp\SharpDevelop"下，代码结构存储到DomCacheDebug目录下，文档注释存储到DocumentationCacheDebug目录下。&lt;br /&gt;首先在ParserService的CreateDefaultProjectContent()中加载默认命名空间的引用：&lt;br /&gt;&lt;br /&gt;CreateDefaultProjectContent()&lt;br /&gt; 1static void CreateDefaultProjectContent()&lt;br /&gt; 2{&lt;br /&gt; 3    LoggingService.Info("Creating default project content");&lt;br /&gt; 4    LoggingService.Debug("Stacktrace is:\n" + Environment.StackTrace);&lt;br /&gt; 5    defaultProjectContent = new DefaultProjectContent();&lt;br /&gt; 6    defaultProjectContent.ReferencedContents.Add(ProjectContentRegistry.Mscorlib);&lt;br /&gt; 7    string[] defaultReferences = new string[] {&lt;br /&gt; 8        "System",&lt;br /&gt; 9        "System.Data",&lt;br /&gt;10        "System.Drawing",&lt;br /&gt;11        "System.Windows.Forms",&lt;br /&gt;12        "System.XML",&lt;br /&gt;13        "Microsoft.VisualBasic",&lt;br /&gt;14    };&lt;br /&gt;15    foreach (string defaultReference in defaultReferences)&lt;br /&gt;16    {&lt;br /&gt;17        //ReferenceProjectItem item = new ReferenceProjectItem(null, defaultReference);&lt;br /&gt;18        IProjectContent pc = ProjectContentRegistry.GetProjectContentForReference(defaultReference);&lt;br /&gt;19        if (pc != null)&lt;br /&gt;20        {&lt;br /&gt;21            defaultProjectContent.ReferencedContents.Add(pc);&lt;br /&gt;22        }&lt;br /&gt;23    }&lt;br /&gt;24}&lt;br /&gt;其中ProjectContentRegistry的GetProjectContentForReference()方法如下：&lt;br /&gt;&lt;br /&gt;GetProjectContentForReference()&lt;br /&gt; 1public static IProjectContent GetProjectContentForReference(string Include)&lt;br /&gt; 2{&lt;br /&gt; 3    // 省略部分代码&lt;br /&gt; 4    Assembly assembly = GetDefaultAssembly(shortName);&lt;br /&gt; 5    ReflectionProjectContent pc;&lt;br /&gt; 6    if (assembly != null)&lt;br /&gt; 7    {&lt;br /&gt; 8        pc = DomPersistence.LoadProjectContentByAssemblyName(assembly.FullName);&lt;br /&gt; 9        if (pc == null)&lt;br /&gt;10        {&lt;br /&gt;11            pc = new ReflectionProjectContent(assembly);&lt;br /&gt;12            DomPersistence.SaveProjectContent(pc);&lt;br /&gt;13        }&lt;br /&gt;14    }&lt;br /&gt;15    else&lt;br /&gt;16    {&lt;br /&gt;17        pc = LoadProjectContent(itemFileName, itemInclude);&lt;br /&gt;18    }&lt;br /&gt;19    // 省略部分代码&lt;br /&gt;20    return pc;&lt;br /&gt;21}&lt;br /&gt;22static Assembly GetDefaultAssembly(string shortName)&lt;br /&gt;23{&lt;br /&gt;24    // These assemblies are already loaded by SharpDevelop, so we don't need to load&lt;br /&gt;25    // them in a separate AppDomain.&lt;br /&gt;26    switch (shortName) {&lt;br /&gt;27        case "System": // System != mscorlib !!!&lt;br /&gt;28            return SystemAssembly;&lt;br /&gt;29        case "System.Data":&lt;br /&gt;30            return typeof(System.Data.DataException).Assembly;&lt;br /&gt;31        case "System.Design":&lt;br /&gt;32            return typeof(System.ComponentModel.Design.DesignSurface).Assembly;&lt;br /&gt;33        case "System.DirectoryServices":&lt;br /&gt;34            return typeof(System.DirectoryServices.AuthenticationTypes).Assembly;&lt;br /&gt;35        case "System.Drawing":&lt;br /&gt;36            return typeof(System.Drawing.Color).Assembly;&lt;br /&gt;37        case "System.Web.Services":&lt;br /&gt;38            return typeof(System.Web.Services.WebService).Assembly;&lt;br /&gt;39        case "System.Windows.Forms":&lt;br /&gt;40            return typeof(System.Windows.Forms.Control).Assembly;&lt;br /&gt;41        case "System.Xml":&lt;br /&gt;42        case "System.XML":&lt;br /&gt;43            return typeof(XmlReader).Assembly;&lt;br /&gt;44        case "Microsoft.Build.Engine":&lt;br /&gt;45            return typeof(Microsoft.Build.BuildEngine.BuildSettings).Assembly;&lt;br /&gt;46        case "Microsoft.Build.Framework":&lt;br /&gt;47            return typeof(Microsoft.Build.Framework.LoggerVerbosity).Assembly;&lt;br /&gt;48        default:&lt;br /&gt;49            return null;&lt;br /&gt;50    }&lt;br /&gt;51}&lt;br /&gt;可以看到DomPersistence类的作用即在加载或保存dll的代码结构数据, 如果尚未有分析过的数据，则在ReflectionProjectContnet类的构造函数中加以分析，同时调用XmlDoc类的相关方法加载、保存文档注释数据。&lt;br /&gt;&lt;br /&gt;(5)对于文件的转换：&lt;br /&gt;[略]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3、Parser应用: MouseHover Tooltip&lt;br /&gt;注意在SharpEditor项目中有个DebuggerService类，它提供了一个重要方法如下：&lt;br /&gt;&lt;br /&gt;BindTextAreaEvent()&lt;br /&gt;1public static void BindTextAreaEvent(TextEditorControl control)&lt;br /&gt;2{&lt;br /&gt;3    TextArea textArea = control.ActiveTextAreaControl.TextArea;&lt;br /&gt;4    //textArea.IconBarMargin.MouseDown += IconBarMouseDown;&lt;br /&gt;5    textArea.ToolTipRequest -= TextArea_ToolTipRequest;&lt;br /&gt;6    textArea.ToolTipRequest += TextArea_ToolTipRequest;&lt;br /&gt;7}&lt;br /&gt;此方法即用以绑定需要鼠标悬浮提示的TextEditor控件，在SharpPad项目的Open菜单类方法中调用此类绑定编辑控件。&lt;br /&gt;注意上面的方法中可以看到ICSharpCode.TextEditor控件是通过其TextArea的ToolTipRequest事件公开给外部，用以分析并由外部提供ToolTip数据，而TextArea_ToolTipRequest(object sender, ToolTipRequestEventArgs e)方法中根据鼠标位置分析出要显示的数据后，最终调用e.ShowToolTip(toolTipText);用以设置提供数据。&lt;br /&gt;&lt;br /&gt;TextArea_ToolTipRequest()&lt;br /&gt; 1static void TextArea_ToolTipRequest(object sender, ToolTipRequestEventArgs e)&lt;br /&gt; 2{&lt;br /&gt; 3    try&lt;br /&gt; 4    {&lt;br /&gt; 5        TextArea textArea = (TextArea)sender;&lt;br /&gt; 6        if (e.ToolTipShown) return;&lt;br /&gt; 7        if (oldToolTipControl != null &amp;&amp; !oldToolTipControl.AllowClose) return;&lt;br /&gt; 8        if (!CodeCompletionOptions.TooltipsEnabled) return;&lt;br /&gt; 9&lt;br /&gt;10        if (CodeCompletionOptions.TooltipsOnlyWhenDebugging)&lt;br /&gt;11        {&lt;br /&gt;12            if (currentDebugger == null) return;&lt;br /&gt;13            if (!currentDebugger.IsDebugging) return;&lt;br /&gt;14        }&lt;br /&gt;15&lt;br /&gt;16        if (e.InDocument)&lt;br /&gt;17        {&lt;br /&gt;18            Point logicPos = e.LogicalPosition;&lt;br /&gt;19            IDocument doc = textArea.Document;&lt;br /&gt;20            IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(textArea.MotherTextEditorControl.FileName);&lt;br /&gt;21            if (expressionFinder == null)&lt;br /&gt;22                return;&lt;br /&gt;23            LineSegment seg = doc.GetLineSegment(logicPos.Y);&lt;br /&gt;24            if (logicPos.X &gt; seg.Length - 1)&lt;br /&gt;25                return;&lt;br /&gt;26            string textContent = doc.TextContent;&lt;br /&gt;27            ExpressionResult expressionResult = expressionFinder.FindFullExpression(textContent, seg.Offset + logicPos.X);&lt;br /&gt;28            string expression = expressionResult.Expression;&lt;br /&gt;29            if (expression != null &amp;&amp; expression.Length &gt; 0)&lt;br /&gt;30            {&lt;br /&gt;31                // Look if it is variable&lt;br /&gt;32                ResolveResult result = ParserService.Resolve(expressionResult, logicPos.Y + 1, logicPos.X + 1, textArea.MotherTextEditorControl.FileName, textContent);&lt;br /&gt;33                bool debuggerCanShowValue;&lt;br /&gt;34                string toolTipText = GetText(result, expression, out debuggerCanShowValue);&lt;br /&gt;35                DebuggerGridControl toolTipControl = null;&lt;br /&gt;36                if (toolTipText != null)&lt;br /&gt;37                {&lt;br /&gt;38                    if (Control.ModifierKeys == Keys.Control)&lt;br /&gt;39                    {&lt;br /&gt;40                        toolTipText = "expr: " + expressionResult.ToString() + "\n" + toolTipText;&lt;br /&gt;41                    }&lt;br /&gt;42                    else if (debuggerCanShowValue &amp;&amp; currentDebugger != null)&lt;br /&gt;43                    {&lt;br /&gt;44                        toolTipControl = currentDebugger.GetTooltipControl(expressionResult.Expression);&lt;br /&gt;45                        toolTipText = null;&lt;br /&gt;46                    }&lt;br /&gt;47                }&lt;br /&gt;48                if (toolTipText != null)&lt;br /&gt;49                {&lt;br /&gt;50                    e.ShowToolTip(toolTipText);&lt;br /&gt;51                }&lt;br /&gt;52                if (oldToolTipControl != null)&lt;br /&gt;53                {&lt;br /&gt;54                    Form frm = oldToolTipControl.FindForm();&lt;br /&gt;55                    if (frm != null) frm.Close();&lt;br /&gt;56                }&lt;br /&gt;57                if (toolTipControl != null)&lt;br /&gt;58                {&lt;br /&gt;59                    toolTipControl.ShowForm(textArea, logicPos);&lt;br /&gt;60                }&lt;br /&gt;61                oldToolTipControl = toolTipControl;&lt;br /&gt;62            }&lt;br /&gt;63        }&lt;br /&gt;64    }&lt;br /&gt;65    catch (Exception ex)&lt;br /&gt;66    {&lt;br /&gt;67        MessageBox.Show(ex.ToString());&lt;br /&gt;68    }&lt;br /&gt;69}&lt;br /&gt;&lt;br /&gt;4、Parser应用: CodeCompletion &amp; MethodInsight&lt;br /&gt;ICSharpCode.TextEditor控件使用ICompletionData类以及ICompletionDataProvider接口(GenerateCompletionData()方法)定义数据自动完成列表的数据及其提供者: SharpEditor项目中的AbstractCodeCompletionDataProvider类中由GetExpression()及AddResolveResults()两个辅助方法生成数据，代码如下：&lt;br /&gt;&lt;br /&gt;AbstractCodeCompletionDataProvider 类&lt;br /&gt; 1protected ArrayList completionData = null;&lt;br /&gt; 2// &lt;br /&gt; 3protected ExpressionResult GetExpression(TextArea textArea)&lt;br /&gt; 4{&lt;br /&gt; 5    IDocument document = textArea.Document;&lt;br /&gt; 6    IExpressionFinder expressionFinder = ParserService.GetExpressionFinder(fileName);&lt;br /&gt; 7    if (expressionFinder == null) {&lt;br /&gt; 8        return new ExpressionResult(TextUtilities.GetExpressionBeforeOffset(textArea, textArea.Caret.Offset));&lt;br /&gt; 9    } else {&lt;br /&gt;10        ExpressionResult res = expressionFinder.FindExpression(document.GetText(0, textArea.Caret.Offset), textArea.Caret.Offset - 1);&lt;br /&gt;11        if (overrideContext != null)&lt;br /&gt;12            res.Context = overrideContext;&lt;br /&gt;13        return res;&lt;br /&gt;14    }&lt;br /&gt;15}&lt;br /&gt;16protected void AddResolveResults(ResolveResult results, ExpressionContext context)&lt;br /&gt;17{&lt;br /&gt;18    insertedElements.Clear();&lt;br /&gt;19    insertedPropertiesElements.Clear();&lt;br /&gt;20    insertedEventElements.Clear();&lt;br /&gt;21    &lt;br /&gt;22    if (results != null) {&lt;br /&gt;23        AddResolveResults(results.GetCompletionData(ParserService.CurrentProjectContent), context);&lt;br /&gt;24    }&lt;br /&gt;25}&lt;br /&gt;26protected void AddResolveResults(ICollection list, ExpressionContext context)&lt;br /&gt;27{&lt;br /&gt;28    if (list == null) {&lt;br /&gt;29        return;&lt;br /&gt;30    }&lt;br /&gt;31    completionData.Capacity += list.Count;&lt;br /&gt;32    CodeCompletionData suggestedData = null;&lt;br /&gt;33    foreach (object o in list) {&lt;br /&gt;34        if (context != null &amp;&amp; !context.ShowEntry(o))&lt;br /&gt;35            continue;&lt;br /&gt;36        CodeCompletionData ccd = CreateItem(o, context);&lt;br /&gt;37        if (object.Equals(o, context.SuggestedItem))&lt;br /&gt;38            suggestedData = ccd;&lt;br /&gt;39        if (ccd != null &amp;&amp; !ccd.Text.StartsWith("___"))&lt;br /&gt;40            completionData.Add(ccd);&lt;br /&gt;41    }&lt;br /&gt;42    if (context.SuggestedItem != null) {&lt;br /&gt;43        if (suggestedData == null) {&lt;br /&gt;44            suggestedData = CreateItem(context.SuggestedItem, context);&lt;br /&gt;45            if (suggestedData != null) {&lt;br /&gt;46                completionData.Add(suggestedData);&lt;br /&gt;47            }&lt;br /&gt;48        }&lt;br /&gt;49        if (suggestedData != null) {&lt;br /&gt;50            completionData.Sort();&lt;br /&gt;51            this.DefaultIndex = completionData.IndexOf(suggestedData);&lt;br /&gt;52        }&lt;br /&gt;53    }&lt;br /&gt;54}&lt;br /&gt;CommentCompletionDataProvider类提供注释的自动完成，相关代码如下：&lt;br /&gt;&lt;br /&gt;CommentCompletionDataProvider 类&lt;br /&gt; 1string[][] commentTags = new string[][] {&lt;br /&gt; 2    new string[] {"c", "marks text as code"},&lt;br /&gt; 3    new string[] {"code", "marks text as code"},&lt;br /&gt; 4    new string[] {"example", "A description of the code example\n(must have a &lt;code&gt; tag inside)"},&lt;br /&gt; 5    new string[] {"exception cref=\"\"", "description to an exception thrown"},&lt;br /&gt; 6    new string[] {"list type=\"\"", "A list"},&lt;br /&gt; 7    new string[] {"listheader", "The header from the list"},&lt;br /&gt; 8    new string[] {"item", "A list item"},&lt;br /&gt; 9    new string[] {"term", "A term in a list"},&lt;br /&gt;10    new string[] {"description", "A description to a term in a list"},&lt;br /&gt;11    new string[] {"para", "A text paragraph"},&lt;br /&gt;12    new string[] {"param name=\"\"", "A description for a parameter"},&lt;br /&gt;13    new string[] {"paramref name=\"\"", "A reference to a parameter"},&lt;br /&gt;14    new string[] {"permission cref=\"\"", ""},&lt;br /&gt;15    new string[] {"remarks", "Gives description for a member"},&lt;br /&gt;16    new string[] {"include file=\"\" path=\"\"", "Includes comments from other files"},&lt;br /&gt;17    new string[] {"returns", "Gives description for a return value"},&lt;br /&gt;18    new string[] {"see cref=\"\"", "A reference to a member"},&lt;br /&gt;19    new string[] {"seealso cref=\"\"", "A reference to a member in the seealso section"},&lt;br /&gt;20    new string[] {"summary", "A summary of the object"},&lt;br /&gt;21    new string[] {"value", "A description of a property"}&lt;br /&gt;22};&lt;br /&gt;23public override ICompletionData[] GenerateCompletionData(string fileName, TextArea textArea, char charTyped)&lt;br /&gt;24{&lt;br /&gt;25    caretLineNumber = textArea.Caret.Line;&lt;br /&gt;26    caretColumn     = textArea.Caret.Column;&lt;br /&gt;27    LineSegment caretLine = textArea.Document.GetLineSegment(caretLineNumber);&lt;br /&gt;28    string lineText = textArea.Document.GetText(caretLine.Offset, caretLine.Length);&lt;br /&gt;29    if (!lineText.Trim().StartsWith("///") &amp;&amp; !lineText.Trim().StartsWith("'''")) {&lt;br /&gt;30        return null;&lt;br /&gt;31    }&lt;br /&gt;32    &lt;br /&gt;33    ArrayList completionData = new ArrayList();&lt;br /&gt;34    foreach (string[] tag in commentTags) {&lt;br /&gt;35        completionData.Add(new CommentCompletionData(tag[0], tag[1]));&lt;br /&gt;36    }&lt;br /&gt;37    return (ICompletionData[])completionData.ToArray(typeof(ICompletionData));&lt;br /&gt;38}&lt;br /&gt;类似地，ICSharpCode.TextEditor控件提供了IInsightDataProvider接口(GetInsightData()方法)，SharpEditor项目中实现类MethodInsightDataProvider和IndexerInsightDataProvider提供相关数据。&lt;br /&gt;&lt;br /&gt;除了上面需要提供数据的类外，还要绑定TextEditor的TextArea的KeyEventHandler事件(详见SharpEditor项目的SharpDevelopTextAreaControl.cs)，其中辅助类的处理代码如下：&lt;br /&gt;&lt;br /&gt;KeyEventHandler 事件响应&lt;br /&gt;  1// 默认处理 DefaultCodeCompletionBinding(详见SharpEditor项目的CodeCompletionBinding.cs):&lt;br /&gt;  2public virtual bool HandleKeyPress(SharpDevelopTextAreaControl editor, char ch)&lt;br /&gt;  3{&lt;br /&gt;  4    switch (ch)&lt;br /&gt;  5    {&lt;br /&gt;  6        case '(':&lt;br /&gt;  7            if (enableMethodInsight &amp;&amp; CodeCompletionOptions.InsightEnabled)&lt;br /&gt;  8            {&lt;br /&gt;  9                editor.ShowInsightWindow(new MethodInsightDataProvider());&lt;br /&gt; 10                return true;&lt;br /&gt; 11            }&lt;br /&gt; 12            else&lt;br /&gt; 13            {&lt;br /&gt; 14                return false;&lt;br /&gt; 15            }&lt;br /&gt; 16        case '[':&lt;br /&gt; 17            if (enableIndexerInsight &amp;&amp; CodeCompletionOptions.InsightEnabled)&lt;br /&gt; 18            {&lt;br /&gt; 19                editor.ShowInsightWindow(new IndexerInsightDataProvider());&lt;br /&gt; 20                return true;&lt;br /&gt; 21            }&lt;br /&gt; 22            else&lt;br /&gt; 23            {&lt;br /&gt; 24                return false;&lt;br /&gt; 25            }&lt;br /&gt; 26        case '&lt;':&lt;br /&gt; 27            if (enableXmlCommentCompletion)&lt;br /&gt; 28            {&lt;br /&gt; 29                editor.ShowCompletionWindow(new CommentCompletionDataProvider(), ch);&lt;br /&gt; 30                return true;&lt;br /&gt; 31            }&lt;br /&gt; 32            else&lt;br /&gt; 33            {&lt;br /&gt; 34                return false;&lt;br /&gt; 35            }&lt;br /&gt; 36        case '.':&lt;br /&gt; 37            if (enableDotCompletion)&lt;br /&gt; 38            {&lt;br /&gt; 39                editor.ShowCompletionWindow(new CodeCompletionDataProvider(), ch);&lt;br /&gt; 40                return true;&lt;br /&gt; 41            }&lt;br /&gt; 42            else&lt;br /&gt; 43            {&lt;br /&gt; 44                return false;&lt;br /&gt; 45            }&lt;br /&gt; 46        case ' ':&lt;br /&gt; 47            if (!CodeCompletionOptions.KeywordCompletionEnabled)&lt;br /&gt; 48                return false;&lt;br /&gt; 49            string word = editor.GetWordBeforeCaret();&lt;br /&gt; 50            if (word != null)&lt;br /&gt; 51                return HandleKeyword(editor, word);&lt;br /&gt; 52            else&lt;br /&gt; 53                return false;&lt;br /&gt; 54        default:&lt;br /&gt; 55            return false;&lt;br /&gt; 56    }&lt;br /&gt; 57}&lt;br /&gt; 58// .cs 文件的处理(详见CSharpBinding项目的CSharpCompletionBinding.cs)：&lt;br /&gt; 59public override bool HandleKeyPress(SharpDevelopTextAreaControl editor, char ch)&lt;br /&gt; 60{&lt;br /&gt; 61    Parser.ExpressionFinder ef = new Parser.ExpressionFinder(editor.FileName);&lt;br /&gt; 62    int cursor = editor.ActiveTextAreaControl.Caret.Offset;&lt;br /&gt; 63    ExpressionContext context = null;&lt;br /&gt; 64    if (ch == '(')&lt;br /&gt; 65    {&lt;br /&gt; 66        if (CodeCompletionOptions.KeywordCompletionEnabled)&lt;br /&gt; 67        {&lt;br /&gt; 68            switch (editor.GetWordBeforeCaret().Trim())&lt;br /&gt; 69            {&lt;br /&gt; 70                case "for":&lt;br /&gt; 71                case "lock":&lt;br /&gt; 72                    context = ExpressionContext.Default;&lt;br /&gt; 73                    break;&lt;br /&gt; 74                case "using":&lt;br /&gt; 75                    context = ExpressionContext.TypeDerivingFrom(ReflectionReturnType.Disposable.GetUnderlyingClass(), false);&lt;br /&gt; 76                    break;&lt;br /&gt; 77                case "catch":&lt;br /&gt; 78                    context = ExpressionContext.TypeDerivingFrom(ReflectionReturnType.Exception.GetUnderlyingClass(), false);&lt;br /&gt; 79                    break;&lt;br /&gt; 80                case "foreach":&lt;br /&gt; 81                case "typeof":&lt;br /&gt; 82                case "sizeof":&lt;br /&gt; 83                case "default":&lt;br /&gt; 84                    context = ExpressionContext.Type;&lt;br /&gt; 85                    break;&lt;br /&gt; 86            }&lt;br /&gt; 87        }&lt;br /&gt; 88        if (context != null)&lt;br /&gt; 89        {&lt;br /&gt; 90            if (IsInComment(editor)) return false;&lt;br /&gt; 91            editor.ShowCompletionWindow(new CtrlSpaceCompletionDataProvider(context), ch);&lt;br /&gt; 92            return true;&lt;br /&gt; 93        }&lt;br /&gt; 94        else if (EnableMethodInsight &amp;&amp; CodeCompletionOptions.InsightEnabled)&lt;br /&gt; 95        {&lt;br /&gt; 96            editor.ShowInsightWindow(new MethodInsightDataProvider());&lt;br /&gt; 97            return true;&lt;br /&gt; 98        }&lt;br /&gt; 99        return false;&lt;br /&gt;100    }&lt;br /&gt;101    else if (ch == '[')&lt;br /&gt;102    {&lt;br /&gt;103        LineSegment line = editor.Document.GetLineSegmentForOffset(cursor);&lt;br /&gt;104        if (TextUtilities.FindPrevWordStart(editor.Document, cursor) &lt;= line.Offset)&lt;br /&gt;105        {&lt;br /&gt;106            // [ is first character on the line&lt;br /&gt;107            // -&gt; Attribute completion&lt;br /&gt;108            editor.ShowCompletionWindow(new AttributesDataProvider(), ch);&lt;br /&gt;109            return true;&lt;br /&gt;110        }&lt;br /&gt;111    }&lt;br /&gt;112    else if (ch == ',' &amp;&amp; CodeCompletionOptions.InsightRefreshOnComma &amp;&amp; CodeCompletionOptions.InsightEnabled)&lt;br /&gt;113    {&lt;br /&gt;114        // Show MethodInsightWindow or IndexerInsightWindow&lt;br /&gt;115        string documentText = editor.Text;&lt;br /&gt;116        int oldCursor = cursor;&lt;br /&gt;117        string textWithoutComments = ef.FilterComments(documentText, ref cursor);&lt;br /&gt;118        int commentLength = oldCursor - cursor;&lt;br /&gt;119        if (textWithoutComments != null)&lt;br /&gt;120        {&lt;br /&gt;121            Stack&lt;ResolveResult&gt; parameters = new Stack&lt;ResolveResult&gt;();&lt;br /&gt;122            char c = '\0';&lt;br /&gt;123            while (cursor &gt; 0)&lt;br /&gt;124            {&lt;br /&gt;125                while (--cursor &gt; 0 &amp;&amp;&lt;br /&gt;126                       ((c = textWithoutComments[cursor]) == ',' ||&lt;br /&gt;127                        char.IsWhiteSpace(c))) ;&lt;br /&gt;128                if (c == '(')&lt;br /&gt;129                {&lt;br /&gt;130                    ShowInsight(editor, new MethodInsightDataProvider(cursor + commentLength, true), parameters, ch);&lt;br /&gt;131                    return true;&lt;br /&gt;132                }&lt;br /&gt;133                else if (c == '[')&lt;br /&gt;134                {&lt;br /&gt;135                    ShowInsight(editor, new IndexerInsightDataProvider(cursor + commentLength, true), parameters, ch);&lt;br /&gt;136                    return true;&lt;br /&gt;137                }&lt;br /&gt;138                string expr = ef.FindExpressionInternal(textWithoutComments, cursor);&lt;br /&gt;139                if (expr == null || expr.Length == 0)&lt;br /&gt;140                    break;&lt;br /&gt;141                parameters.Push(ParserService.Resolve(new ExpressionResult(expr),&lt;br /&gt;142                                                      editor.ActiveTextAreaControl.Caret.Line,&lt;br /&gt;143                                                      editor.ActiveTextAreaControl.Caret.Column,&lt;br /&gt;144                                                      editor.FileName,&lt;br /&gt;145                                                      documentText));&lt;br /&gt;146                cursor = ef.LastExpressionStartPosition;&lt;br /&gt;147            }&lt;br /&gt;148        }&lt;br /&gt;149    }&lt;br /&gt;150    else if (ch == '=')&lt;br /&gt;151    {&lt;br /&gt;152        LineSegment curLine = editor.Document.GetLineSegmentForOffset(cursor);&lt;br /&gt;153        string documentText = editor.Text;&lt;br /&gt;154        int position = editor.ActiveTextAreaControl.Caret.Offset - 2;&lt;br /&gt;155&lt;br /&gt;156        if (position &gt; 0 &amp;&amp; (documentText[position + 1] == '+'))&lt;br /&gt;157        {&lt;br /&gt;158            ExpressionResult result = ef.FindFullExpression(documentText, position);&lt;br /&gt;159&lt;br /&gt;160            if (result.Expression != null)&lt;br /&gt;161            {&lt;br /&gt;162                ResolveResult resolveResult = ParserService.Resolve(result, editor.ActiveTextAreaControl.Caret.Line, editor.ActiveTextAreaControl.Caret.Column, editor.FileName, documentText);&lt;br /&gt;163                if (resolveResult != null &amp;&amp; resolveResult.ResolvedType != null)&lt;br /&gt;164                {&lt;br /&gt;165                    IClass underlyingClass = resolveResult.ResolvedType.GetUnderlyingClass();&lt;br /&gt;166                    if (underlyingClass != null &amp;&amp; underlyingClass.IsTypeInInheritanceTree(ProjectContentRegistry.Mscorlib.GetClass("System.MulticastDelegate")))&lt;br /&gt;167                    {&lt;br /&gt;168                        EventHandlerCompletitionDataProvider eventHandlerProvider = new EventHandlerCompletitionDataProvider(result.Expression, resolveResult);&lt;br /&gt;169                        eventHandlerProvider.InsertSpace = true;&lt;br /&gt;170                        editor.ShowCompletionWindow(eventHandlerProvider, ch);&lt;br /&gt;171                    }&lt;br /&gt;172                }&lt;br /&gt;173            }&lt;br /&gt;174        }&lt;br /&gt;175    }&lt;br /&gt;176    else if (ch == ';')&lt;br /&gt;177    {&lt;br /&gt;178        LineSegment curLine = editor.Document.GetLineSegmentForOffset(cursor);&lt;br /&gt;179        // don't return true when inference succeeds, otherwise the ';' won't be added to the document.&lt;br /&gt;180        TryDeclarationTypeInference(editor, curLine);&lt;br /&gt;181    }&lt;br /&gt;182&lt;br /&gt;183    return base.HandleKeyPress(editor, ch);&lt;br /&gt;184}&lt;br /&gt;&lt;br /&gt;5、Parser应用: QuickClassBrowserPanel&lt;br /&gt;QuickClassBrowserPanel即编辑窗口顶部的类及成员快速浏览窗口，其实现如下：&lt;br /&gt;首先在SharpDevelopTextAreaControl类中重写override void OnFileNameChanged(EventArgs e)方法，即打开新文件时，调用ActivateQuickClassBrowserOnDemand()来根据是否有能够分析此文件的Parser来决定是否显示控件，如果可以显示，则实例化出一个新对象，并添加进来。实例化QuickClassBrowserPanel对象的相关代码如下：&lt;br /&gt;&lt;br /&gt;QuickClassBrowserPanel&lt;br /&gt; 1private System.Windows.Forms.ComboBox classComboBox;&lt;br /&gt; 2private System.Windows.Forms.ComboBox membersComboBox;&lt;br /&gt; 3ICompilationUnit            currentCompilationUnit;&lt;br /&gt; 4// &lt;br /&gt; 5public QuickClassBrowserPanel(SharpDevelopTextAreaControl textAreaControl)&lt;br /&gt; 6{&lt;br /&gt; 7    InitializeComponent();&lt;br /&gt; 8    this.membersComboBox.MaxDropDownItems = 20;&lt;br /&gt; 9&lt;br /&gt;10    base.Dock = DockStyle.Top;&lt;br /&gt;11    this.textAreaControl = textAreaControl;&lt;br /&gt;12    this.textAreaControl.ActiveTextAreaControl.Caret.PositionChanged += new EventHandler(CaretPositionChanged);&lt;br /&gt;13}&lt;br /&gt;14void CaretPositionChanged(object sender, EventArgs e)&lt;br /&gt;15{&lt;br /&gt;16    // ignore simple movements&lt;br /&gt;17    if (e != EventArgs.Empty) {&lt;br /&gt;18        return;&lt;br /&gt;19    }&lt;br /&gt;20    try {&lt;br /&gt;21        &lt;br /&gt;22        ParseInformation parseInfo = ParserService.GetParseInformation(textAreaControl.FileName);&lt;br /&gt;23        if (parseInfo != null) {&lt;br /&gt;24            if (currentCompilationUnit != (ICompilationUnit)parseInfo.MostRecentCompilationUnit) {&lt;br /&gt;25                currentCompilationUnit = (ICompilationUnit)parseInfo.MostRecentCompilationUnit;&lt;br /&gt;26                if (currentCompilationUnit != null) {&lt;br /&gt;27                    &lt;br /&gt;28                    FillClassComboBox(true);&lt;br /&gt;29                    FillMembersComboBox();&lt;br /&gt;30                }&lt;br /&gt;31            }&lt;br /&gt;32            UpdateClassComboBox();&lt;br /&gt;33            UpdateMembersComboBox();&lt;br /&gt;34        }&lt;br /&gt;35    } catch (Exception ex) {&lt;br /&gt;36        MessageService.ShowError(ex);&lt;br /&gt;37    }&lt;br /&gt;38}&lt;br /&gt;可以看到类、成员列表的ComboBox数据的填充是在textAreaControl.ActiveTextAreaControl.Caret.PositionChanged事件后执行，因为光标位置的改变可能需要同步更新顶部列表框的显示；注意两个列表的列表项使用自定义类ComboBoxItem, 包括成员的Line, Column等信息；该类中绑定两个列表的SelectedIndexChange事件用以在编辑器中定位相应的类或成员位置：&lt;br /&gt;&lt;br /&gt;ComboBoxSelectedIndexChanged()&lt;br /&gt; 1void ComboBoxSelectedIndexChanged(object sender, System.EventArgs e)&lt;br /&gt; 2{&lt;br /&gt; 3    ComboBox comboBox = (ComboBox)sender;&lt;br /&gt; 4    if (autoselect) {&lt;br /&gt; 5        ComboBoxItem item = (ComboBoxItem)comboBox.Items[comboBox.SelectedIndex];&lt;br /&gt; 6        if (item.IsInCurrentPart)&lt;br /&gt; 7        {&lt;br /&gt; 8            textAreaControl.ActiveTextAreaControl.Caret.Position = new Point(item.Column, item.Line);&lt;br /&gt; 9            textAreaControl.ActiveTextAreaControl.TextArea.Focus();&lt;br /&gt;10        }&lt;br /&gt;11    }&lt;br /&gt;12}&lt;br /&gt;&lt;br /&gt;6、Parser应用: Folding&lt;br /&gt;ICSharpCode.TextEditor控件提供了IFoldingStrategy接口用以定义代码折叠需实现的方法：&lt;br /&gt;&lt;br /&gt;IFoldingStrategy 接口&lt;br /&gt; 1/**//// &lt;summary&gt;&lt;br /&gt; 2/// This interface is used for the folding capabilities&lt;br /&gt; 3/// of the textarea.&lt;br /&gt; 4/// &lt;/summary&gt;&lt;br /&gt; 5public interface IFoldingStrategy&lt;br /&gt; 6{&lt;br /&gt; 7    /**//// &lt;remarks&gt;&lt;br /&gt; 8    /// Calculates the fold level of a specific line.&lt;br /&gt; 9    /// &lt;/remarks&gt;&lt;br /&gt;10    List&lt;FoldMarker&gt; GenerateFoldMarkers(IDocument document, string fileName, object parseInformation);&lt;br /&gt;11}&lt;br /&gt;SharpEditor项目中，SharpDevelopTextAreaControl在构造函数中指明了FoldingStrategy:&lt;br /&gt;&lt;br /&gt;SharpDevelopTextAreaControl 构造函数&lt;br /&gt; 1public SharpDevelopTextAreaControl()&lt;br /&gt; 2{&lt;br /&gt; 3    Document.FoldingManager.FoldingStrategy = new ParserFoldingStrategy();&lt;br /&gt; 4&lt;br /&gt; 5    // 由于UpdateClassMemberBookmarks()方法中以Bookmark形式显示方法、属性、变量等&lt;br /&gt; 6    // 故此处需要定义Bookmark Factory 以使上面的Bookmark 与用户加入的书签区别开&lt;br /&gt; 7    Document.BookmarkManager.Factory = new Bookmarks.SDBookmarkFactory(Document.BookmarkManager);&lt;br /&gt; 8}&lt;br /&gt; 9protected override void OnFileNameChanged(EventArgs e)&lt;br /&gt;10{&lt;br /&gt;11    base.OnFileNameChanged(e);&lt;br /&gt;12    ActivateQuickClassBrowserOnDemand();&lt;br /&gt;13    ForceFoldingUpdate();&lt;br /&gt;14}&lt;br /&gt;15void ForceFoldingUpdate()&lt;br /&gt;16{&lt;br /&gt;17    ParseInformation parseInfo = ParserService.GetParseInformation(FileName);&lt;br /&gt;18    if (parseInfo == null)&lt;br /&gt;19    {&lt;br /&gt;20        parseInfo = ParserService.ParseFile(FileName, Document.TextContent, false, false);&lt;br /&gt;21    }&lt;br /&gt;22    Document.FoldingManager.UpdateFoldings(FileName, parseInfo);&lt;br /&gt;23    &lt;br /&gt;24    // 在编辑器的类、属性、变量等行左侧显示相应图标&lt;br /&gt;25    UpdateClassMemberBookmarks(parseInfo);&lt;br /&gt;26}&lt;br /&gt;同样需要在打开新文件时调用更新代码折叠标签，代码折叠FoldMarker生成的具体实现详见SharpEditor项目的ParserFoldingStrategy.cs&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;7、总结&lt;br /&gt;上面简要介绍了Parser的部分实现, 期待有相关经验的网友指定我的理解错误或给予补充解释。&lt;br /&gt;以及Parser的部分应用：MouseHover Tooltip, CodeCompletion &amp; MethodInsight, QuickClassBrowserPanel, Folding；SharpDevelop中的其它应用如类视图ClassBrowser, 对象浏览AssemblyPad(SharpDevelop2.0源码中未见到?).&lt;br /&gt;&lt;br /&gt;SharpDevelop浅析_5_Windows Forms Designer&lt;br /&gt;自己动手创建应用程序界面设计器&lt;br /&gt;&lt;br /&gt;功能概述:&lt;br /&gt;a, 窗体左侧为工具栏，可以单击、双击、拖曳的方式来添加控件&lt;br /&gt;b, 窗体右侧为属性(事件)窗口及控件(浏览)选择Combo&lt;br /&gt;c, 窗体中部包括设计器及代码查看Tab页&lt;br /&gt;d, 窗体顶部实现了编辑、对齐、运行等命令项&lt;br /&gt;&lt;br /&gt;2、Demo实现简述&lt;br /&gt;a, 设计器的核心是.NET框架提供的DesignSurface类、ServiceContainer类&lt;br /&gt;b, 设计器的扩展点(自定义部分)是通过向ServiceContainer添加自动定义服务类(IOC模式?)或订阅服务类的事件……&lt;br /&gt;c, Demo中的使用或创建的服务类包含了ISelectionService, IComponentChangeService MenuCommandService, CustomToolboxService, NameCreationService, DesignerEventService, EventBindingService.&lt;br /&gt;d, 补充说明: Demo左侧工具栏项目是通过\data\SharpDevelopControlLibrary.xml配置文件定义；窗口中部的代码查看页中使用了SharpDevelop的TextEditorControl.&lt;br /&gt;&lt;br /&gt;3、参考资料&lt;br /&gt;关于自定义窗体设计器的具体设计过程请参照如下资源：&lt;br /&gt;&lt;br /&gt;Create And Host Custom Designers With The .NET Framework 2.0&lt;br /&gt;http://msdn.microsoft.com/msdnmag/issues/06/03/DesignerHosting/default.aspx&lt;br /&gt;&lt;br /&gt;利用 .NET Framework 2.0 创建并宿主自定义的设计&lt;br /&gt;http://www.microsoft.com/china/MSDN/library/netFramework/netframework/ DesignerHosting.mspx?mfr=true&lt;br /&gt;&lt;br /&gt;Hosting Windows Forms Designers&lt;br /&gt;http://www.divil.co.uk/net/articles/designers/hosting.asp&lt;br /&gt;&lt;br /&gt;沧海月明 "写Form设计器尝试"系列&lt;br /&gt;http://www.cnblogs.com/panjiwen/category/36995.html&lt;br /&gt;&lt;br /&gt;Demo中左侧工具栏的控件使用了 纶巾客 写的一个控件：制作VS风格的Toolbox控件&lt;br /&gt;http://www.cnblogs.com/guanjinke/archive/2007/01/10/617092.html&lt;br /&gt;&lt;br /&gt;对该控件的主要修改如下：&lt;br /&gt;ToolBoxItem类添加了Tag及Image属性以存储Tag数据及显示图片&lt;br /&gt;ToolBox增加了SelectedItemChanged, ItemDoubleClicked, ItemDragStart事件&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8972319-5145610219380705022?l=telestarnotes.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/5145610219380705022'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8972319/posts/default/5145610219380705022'/><link rel='alternate' type='text/html' href='http://telestarnotes.blogspot.com/2006/06/some-notes-on-sharpdevelop-2.html' title='Some notes on SharpDevelop - 2'/><author><name>TeleStar</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://bp2.blogger.com/_ss9Afn3j1q8/SBloxIeffSI/AAAAAAAAAAQ/ZlF39A_ClYo/S220/ID.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8972319.post-114671664962302233</id><published>2006-06-14T21:20:00.000-07:00</published><updated>2008-01-15T02:47:24.106-08:00</updated><title type='text'>Some notes on SharpDevelop - 1</title><content type='html'>1.&lt;br /&gt;From http://passos.cnblogs.com/archive/2004/10/04/48950.html&lt;br /&gt;http://passos.cnblogs.com/archive/2004/10/07/49654.html&lt;br /&gt;http://passos.cnblogs.com/archive/2004/10/10/50652.html&lt;br /&gt;http://passos.cnblogs.com/archive/2004/10/15/52513.html&lt;br /&gt;&lt;br /&gt;SharpDevelop代码分析 (一、序+基本概念) &lt;br /&gt;序 &lt;br /&gt;&lt;br /&gt;    最近开始学习.Net，遇到了一个比较不错的开源的IDE SharpDevelop。这个开发工具是使用C#开发的，比较吸引我的一点就是它是采用了和Eclipse类似的插件技术来实现整个系统的。而这个插件系统是我最感兴趣的地方，因此开始了一段代码的研究。在本篇之后，我会陆续把我研究的心得写下来。由于是在网吧上网，有诸多不便，因此可能会拖比较长的时间。 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;一、基本概念 &lt;br /&gt;&lt;br /&gt;    首先，我们先来对 SharpDevelop 有一个比较感性的认识。你可以从这里下载到它的可执行程序和代码包    http://www.icsharpcode.com/  ，安装的废话就不说了，先运行一下看看。感觉跟VS很像吧？不过目前的版本是1.0.0.1550，还有很多地方需要完善。关于代码和系统结构，SharpDevelop的三个作者写了一本书，各位看官可以参考一下，不过我看过之后还是有很多地方不太理解。 &lt;br /&gt;&lt;br /&gt;    然后，让我来解释一下什么叫插件以及为什么要使用插件系统。我们以往的系统，开发人员编译发布之后，系统就不允许进行更改和扩充了，如果要进行某个功能的扩充，则必须要修改代码重新编译发布。这就给我们带来了比较大的不方便。解决的方法有很多，例如提供配置等等方法。在解决方案之中，插件是一个比较好的解决方法。大家一定知道PhotoShop、WinAmp吧，他们都有“插件”的概念，允许其他开发人员根据系统预定的接口编写扩展功能（例如PhotoShop中各种各样的滤镜）。所谓的插件就是系统的扩展功能模块，这个模块是以一个独立文件的形式出现的，与系统是相对独立。在系统设计期间并不知道插件的具体功能，仅仅是在系统中为插件留下预定的接口，系统启动的时候根据插件的配置寻找插件，根据预定的接口把插件挂接到系统中。 &lt;br /&gt;&lt;br /&gt;    这样的方式带来什么样的优点呢？首先是系统的扩展性大大的增强了，如果我们在系统发布后需要对系统进行扩充，不必重新编译，只需要修改插件就可以了。其次有利与团队开发，各个功能模块由于是以插件的形式表现在系统中，系统的每日构造就很简单了，不会因为某个模块的错误而导致整个系统的BUILD失败。失败的仅仅是一个插件而已。 &lt;br /&gt;&lt;br /&gt;    PhotoShop和Winamp的插件系统是比较简单的，他们首先实现了一个基本的系统，然后在这个系统的基础上挂接其他扩展的功能插件。而SharpDevelop的插件系统更加强大，它的整个系统的基础就仅仅是一个插件管理系统，而你看到的所有的界面、功能统统都是以插件的形式挂入的。在这样的一个插件系统下，我们可以不修改基本系统，仅仅使用插件就构造出各种各样不同的系统。 &lt;br /&gt;&lt;br /&gt;    现在让我们来看看它的插件系统。进入到SharpDevelop的安装目录中，在Bin目录下的SharpDevelop.exe 和 SharpDevelop.Core.dll是这个系统的基本的插件系统。在Addins目录下有两个后缀是addin的文件，其中一个 SharpDevelopCore.addin 就是它的核心插件的定义（配置）文件，里面定义的各个功能模块存在于Bin\Sharpdevelop.Base.dll 文件中，另外还有很多其他的插件定义在Addins目录下的addin文件中。 &lt;br /&gt;&lt;br /&gt;    分析SharpDevelop的代码，首先要弄清楚几个基本的概念，这些概念和我以前的预想有一些区别，我深入了代码之后才发现我的困惑所在。 &lt;br /&gt;&lt;br /&gt;1、AddInTree  插件树 &lt;br /&gt;    SharpDevelop 中的插件被组织成一棵插件树结构，树的结构是通过 Extension（扩展点）中定义的Path(路径)来定义的，类似一个文件系统的目录结构。系统中的每一个插件都在配置文件中指定了 Extension，通过Extension中指定的 Path 挂到这棵插件树上。在系统中可以通过 AddTreeSingleton对象来访问各个插件，以实现插件之间的互动。 &lt;br /&gt;&lt;br /&gt;2、 AddIn 插件 &lt;br /&gt;    在 SharpDevelop 的概念中，插件是包含多个功能模块的集合（而不是我过去认为的一个功能模块）。在文件的表现形式上是一个addin配置文件，在系统中对应 AddIn 类。 &lt;br /&gt;&lt;br /&gt;3、Extension 扩展点 &lt;br /&gt;    SharpDevelop中的每一个插件都会被挂到 AddInTree（插件树） 中，而具体挂接到这个插件树的哪个位置，则是由插件的 Extension 对象中的 Path 指定的。在addin 配置文件中，对应于 Extension 。例如下面这个功能模块的配置 &lt;br /&gt;&lt;br /&gt;Extension path = "/SharpDevelop/Workbench/Ambiences" &lt;br /&gt;         Class id    = ".NET" class = "ICSharpCode.SharpDevelop.Services.NetAmbience"/ &lt;br /&gt; /Extension &lt;br /&gt;指定了扩展点路径为 /SharpDevelop/Workbench/Ambiences ，也就是在插件树中的位置。 &lt;br /&gt;&lt;br /&gt;4、Codon &lt;br /&gt;    这个是一个比较不好理解的东西，在 SharpDevelop 的三个作者写的书的中译版中被翻译为密码子，真是个糟糕的翻译，可以跟Handle(句柄)有一拼了。词典中还有一个翻译叫“基码”，我觉得这个也不算好，不过还稍微有那么一点意思。（这里我原来误写为“代码子”，在评论中有位仁兄说这个翻译不错，现在我觉得也好像确实不错 ^o^） &lt;br /&gt;    根据我对代码的理解，Codon 的功能是描述(包装)一个功能模块（一个功能模块对应一个实现了具体功能的 Command 类）。为了方便访问各个插件中的功能模块， Codon 给各种功能定义了基本的属性，分别是 ID (功能模块的标识)，Name (功能模块的类型。别误会，这个Name 是addin文件定义中Codon的XML结点的名称，ID才是真正的名称)，其中Name可能是Class(类)、MenuItem(菜单项)、Pad(面板)等等。根据具体的功能模块，可以继承Codon定义其他的一些属性，SharpDevelop中就定义了 ClassCodon、MenuItemCodon、PadCodon等等，你可以根据需要自己定义其他类型的Codon。在addin定义文件中，Codon对应于 Extension 标签下的内容。例如下面这个定义 &lt;br /&gt;&lt;br /&gt;Extension path = "/SharpDevelop/Workbench/Ambiences" &lt;br /&gt;         Class id    = ".NET" class = "ICSharpCode.SharpDevelop.Services.NetAmbience"/ &lt;br /&gt; /Extension &lt;br /&gt; &lt;br /&gt;Extension ... 内部定义了一个Codon，Class ...  表示该Codon是一个 Class(类)，接着定义了该Codon的 ID和具体实现该Codon的类名ICSharpCode.SharpDevelop.Services.NetAmbience。运行期间将通过反射来找到对应的类并创建出来，这一点也是我们无法在以前的语言中实现的。 &lt;br /&gt;&lt;br /&gt;再例如这一个定义 &lt;br /&gt;&lt;br /&gt; Extension path = "/SharpDevelop/Views/ProjectBrowser/ContextMenu/CombineBrowserNode" &lt;br /&gt;                MenuItem id = "Compile" &lt;br /&gt;                          label = "${res:XML.MainMenu.RunMenu.Compile}"  &lt;br /&gt;                          class = "ICSharpCode.SharpDevelop.Commands.Compile"/ &lt;br /&gt;                MenuItem id = "CompileAll" &lt;br /&gt;                          label = "${res:XML.MainMenu.RunMenu.CompileAll}"  &lt;br /&gt;                          class = "ICSharpCode.SharpDevelop.Commands.CompileAll"/ &lt;br /&gt;                MenuItem id = "CombineBuildGroupSeparator" label = "-" / &lt;br /&gt; . &lt;br /&gt;/Extension &lt;br /&gt; &lt;br /&gt;这个扩展点中定义了三个菜单项，以及各个菜单项的名字、标签和实现的类名。这里的Codon就对应于系统中的MenuCodon对象。 &lt;br /&gt;&lt;br /&gt;5、Command 命令 &lt;br /&gt;    正如前文所述，Codon描述了一个功能模块，而每个功能模块都是一个 ICommand 的实现。最基本的 Command 是  AbstractCommand，根据Codon的不同对应了不同的 Command。例如 MenuItemCodon 对应 MenuItemCommand 等等。 &lt;br /&gt;&lt;br /&gt;6、Service 服务 &lt;br /&gt;    插件系统中，有一些功能是整个系统都要使用的，例如文件访问、资源、消息等等。这些功能都作为插件系统的一个基本功能为整个系统提供服务，我们就叫“服务”好了。为了便于访问，这些服务都统一通过 ServiceManager 来管理。其实服务也是一种类型的插件，它们的扩展点路径在目录树中的 /Workspace/Services 中。 &lt;br /&gt;&lt;br /&gt;    理解了这几个基本的概念之后，就可以看看 SharpDevelop 的代码了。从 src\main\startup.cs 看起吧，之后是addin.cs、addinTree.cs 等等。 &lt;br /&gt;&lt;br /&gt;   写了两个小时了，休息一下。且听下回分解吧。 &lt;br /&gt;&lt;br /&gt;SharpDevelop源码分析 (二、主程序+隐藏的初始化) &lt;br /&gt;    在大学课程里面，我对于模拟电路总是搞不清楚，直到现在也是这样。我总觉得电路图很奇怪，总会问“这部分电路是做什么用的”、“为什么会有这样的效果”。在我的脑海里面，每部分的电路都应该有一定的用处，可是我总是看不明白。我妈妈说，我的思路被软件所固化的太久了，看电路图不应该总是一个个模块的看，正确的方法应该是从电源的一极顺着电路看，一直看到电源的另一极。我现在仍然不懂看电路图，可是以我看代码的经验来说，我觉得分析源代码按照这样的思路来看会比较容易把脉络理清楚。 &lt;br /&gt;     在SharpDevelop的代码中，由于很多的接口和插件的原因，很多代码在看到某个地方会突然失去函数/方法调用的线索。例如看某个函数的实现的时候会跳到一个接口里面去，那是因为这部分功能在运行期才会给一个实现了这个接口的对象来进行具体的执行。从这个角度来说，设计模式也给我们研究代码稍微带来了一点小小的难度。在看Linux下源代码的时候也经常遇到这种问题，在这个时候寻找代码线索比较好的方法是用一个文本搜索工具来搜索相关的关键字。在Linux下我经常会用grep，Windows下面类似UltraEdit的“批量文件查找”功能会很好用（或者“Search And Replace”之类的工具）。这个是我读代码的一点小小的经验，如果你知道有更好的方法，请告诉我让我也学习一下 ? 。 &lt;br /&gt;     我不想大段大段的贴代码出来占地方（空间、带宽，还有各位看官的注意力），在需要的地方我会贴上主要的代码，因此最好能够找代码来对应着看。把代码包解压缩，我把它解到了“F:\SharpDevelop”（如果没有说明，下文都是以此为代码的根目录了）。由于SharpDevelop本身对于察看代码不是很方便，没有“转到定义”之类的功能，因此我建议你把它的代码转成VS的工程来看。不过很可惜，SharpDevelop的工程导出功能现在有问题，如果导出\src\SharpDevelop.cmbx 这个总的复合工程的话会失败（我记得RC1版本是可以成功的，不知道为什么后来的版本反而会出问题），所以只能一个一个工程的导出。 &lt;br /&gt;     好了，让我们来看SharpDevelop的代码吧。 &lt;br /&gt;1、起点 &lt;br /&gt;    在主程序的起点在\src\Main\StartUp\SharpDevelopMain.cs，找到Main函数这就是整个程序的起点了。开始的部分是显示封面窗体并加上命令行控制，其中SplashScreenForm 定义在\src\Main\Base\Gui\Dialogs\SplashScreen.cs文件中，这部分我就不多说了。之后是 &lt;br /&gt;&lt;br /&gt;Application.ThreadException += new ThreadExceptionEventHandler(ShowErrorBox); &lt;br /&gt; &lt;br /&gt;    SharpDevelop为了有效的进行错误报告，因此自己进行了异常的控制。系统出现异常的时候，SharpDevelop会拦截下来弹出它自己的异常提示报告对话框。这个代码就是在这一行实现的。其中 ShowErrorBox 这个方法就在类SharpDevelopMain中，ExceptionBox 定义在\src\Main\StartUp\Dialogs\ExceptionBox.cs中。如果需要进行自己的异常控制，可以学习一下这里的技巧。&lt;br /&gt;&lt;br /&gt;2、充满玄机的初始化 &lt;br /&gt;&lt;br /&gt;string [] addInDirs = ICSharpCode.SharpDevelop.AddInSettingsHandler.GetAddInDirectories( out ignoreDefaultPath ); &lt;br /&gt;AddInTreeSingleton.SetAddInDirectories(addInDirs, ignoreDefaultPath); &lt;br /&gt;    通过AddInSettingsHandler取得插件的目录，并告知AddInTreeSingleton。AddInSettingsHandler定义在\src\Main\StartUp\Dialogs\AddInTreeSettingsHandler.cs中，它通过读取系统配置（App.config）文件中的AddInDirectory节点的Path属性来确定插件的目录位置，或者你也可以通过自己定义的AddInDirectories节来指定插件目录。如果你没有做这些配置，默认的目录在SharpDevelop运行目录的..\Addins目录下。&lt;br /&gt;&lt;br /&gt;ServiceManager.Services.AddService(new MessageService()); &lt;br /&gt;ServiceManager.Services.AddService(new ResourceService()); &lt;br /&gt;ServiceManager.Services.AddService(new IconService()); &lt;br /&gt;    通过ServiceManager(服务管理器)加入三个系统默认的服务，消息服务、资源服务、图标服务。这三个服务中，消息服务是显示各种信息提示，另外两个是属于系统的资源，SharpDevelop通过服务来进行统一调用和管理。 &lt;br /&gt;ServiceManager.Services.InitializeServicesSubsystem("/Workspace/Services"); &lt;br /&gt;&lt;br /&gt;    初始化其他的服务。SharpDevelop把服务定义在插件树的/Workspace/Services这个路径中，凡是在这个路径下的插件都被认为是服务，因此如果你自己定义了一个服务的话，也需要挂到这个路径下（这里就是系统服务的扩展点了）。 &lt;br /&gt;&lt;br /&gt;    注意！这一步中，在我们的眼皮子底下悄悄的进行了一个重要的初始化工作。各位看官请看，ServiceManager 定义在\src\Main\Core\Services\ ServiceManager.cs文件中，察看它的InitializeServicesSubsystem方法，我们发现这样一行 &lt;br /&gt;&lt;br /&gt;AddServices((IService[])AddInTreeSingleton.AddInTree.GetTreeNode(servicesPath).BuildChildItems(this).ToArray(typeof(IService))); &lt;br /&gt;    在这里，AddInTreeSingleton首次调用了AddInTree（插件树）的实例。按照Singleton模式，只有在首次调用的时候才会初始化实例，这里也是同样如此。整个系统的AddInTree是在这一步中进行了初始化工作，稍候我们将详细介绍AddInTree如何进行初始化工作，先顺便看看服务的初始化。在ServiceManager的InitializeServicesSubsystem方法中，通过AddInTree检索服务插件路径下的所有配置，并通过它来读取、建立具体的对象，然后加入到服务列表中。之后通过一个循环，逐个的调用各个服务的InitializeService方法初始化服务。&lt;br /&gt;&lt;br /&gt;    AddInTree的初始化工作容我们稍候再看，先把主体的代码看完。 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;commands = AddInTreeSingleton.AddInTree.GetTreeNode("/Workspace/Autostart").BuildChildItems(null); &lt;br /&gt;for (int i = 0; i  commands.Count - 1; ++i) &lt;br /&gt;{ &lt;br /&gt; ((ICommand)commands[i]).Run(); &lt;br /&gt;} &lt;br /&gt;    /Workspace/Autostart是系统自动运行命令的扩展点路径，定义在这个路径下的插件会在系统启动的时候自动运行。在这里，通过插件树初始化建立处于这个路径下的Command（命令），并逐一执行。BuildChildItems方法的功能是建立这个扩展点下的Command列表，我会在介绍AddTree的时候具体说明它的实现。&lt;br /&gt;&lt;br /&gt;     主程序代码的最后，初始化完毕、关闭封面窗体，然后执行命令列表中最后一个命令（也就是系统的主界面）。在主界面退出的时候，系统卸载所有的服务。 &lt;br /&gt;&lt;br /&gt;    在这部分代码中，我们知道了两个系统指定的扩展点路径 /Workspace/Services 和 /Workspace/Autostart ，我们实现服务和指定系统自动运行命令的时候就可以挂到这两个扩展点路径下了。 &lt;br /&gt;     托反射的福，ServiceManager.Services可以通过类型（接口）来查找具体的实例，也就是GetServices方法。但是ServiceManager的具体实现我们可以容后再看，这里已经不是最紧要的部分了。 &lt;br /&gt;     接下来，我们来看看整个插件系统的核心－AddinTree的代码，看看它是如何通过插件配置进行初始化并建立起整个系统的插件树骨干。 &lt;br /&gt;&lt;br /&gt;SharpDevelop源码分析 (三、插件系统) &lt;br /&gt;&lt;br /&gt;三、插件系统 &lt;br /&gt;&lt;br /&gt;   上回书说到SharpDevelop入口Main函数的结构，ServiceManager.Service在InitializeServicesSubsystem方法中首次调用了AddInTreeSingleton的AddInTree实例，AddInTree在这里进行了初始化。本回进入AddInTree着重讲述SharpDevelop的插件系统。在叙述的时候为了方便起见，对于“插件”和插件具体的“功能模块”这两个词不会特别的区分，各位看官可以从上下文分辨具体的含义（而事实上，SharpDevelop中的“插件”是指.addin配置文件，每一个“插件”都可能会包含多个“功能模块”）。&lt;br /&gt;&lt;br /&gt;1、插件的配置 &lt;br /&gt;   既然说到插件系统，那么我们先来看一看SharpDevelop插件系统的组织形式。 &lt;br /&gt;   很多时候，同一个事物从不同的角度来看会得出不一样的结论，SharpDevelop的插件系统也是如此。在看SharpDevelop的代码以前，按照我对插件的理解，我认为所谓的“插件”就是代表一个功能模块，插件的配置就是描述该插件并指定如何把这个插件挂到系统中。SharpDevelop中有插件树的思想，也就是每一个插件在系统中都有一个扩展点的路径。那么按照我最初对插件的理解，编写插件需要做的就是： &lt;br /&gt;   A、根据插件接口编写功能模块实现一个Command类 &lt;br /&gt;   B、编写一个配置文件，指定Command类的扩展点(Extension)路径，挂到插件树中 &lt;br /&gt;&lt;br /&gt;   之后按照这样的理解，我编写了一个察看插件树的插件AddinTreeView，打算挂到SharpDevelop中去。根据SharpDevelop对插件的定义，我把具体插件的AddinTreeViewCommand实现了之后，编写了一个配置文件AddinTreeView.addin如下：&lt;br /&gt;&lt;br /&gt;AddIn name        = "AddinTreeView" &lt;br /&gt;       author      = "SimonLiu" &lt;br /&gt;       copyright   = "GPL" &lt;br /&gt;       url         = "http://www.icsharpcode.net" &lt;br /&gt;       description = "Display AddinTree" &lt;br /&gt;       version     = "1.0.0" &lt;br /&gt; &lt;br /&gt; Runtime &lt;br /&gt;  Import assembly="../../bin/ AddinTreeView.dll"/ &lt;br /&gt; /Runtime &lt;br /&gt; &lt;br /&gt; Extension path = "/SharpDevelop/Workbench/MainMenu/Tools" &lt;br /&gt;  MenuItem id = "AddinTreeView"  &lt;br /&gt;   label = "View AddinTree"  &lt;br /&gt;   class = "Addins.AddinTreeView.AddinTreeViewCommand"/ &lt;br /&gt; /Extension  &lt;br /&gt;/AddIn &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;br /&gt;   在配置文件中，Runtime节指定了插件功能模块所在的库文件Addins.dll的具体路径，在Extension节中指定了扩展点路径/SharpDevelop/Workbench/MainMenu/Tools（我是打算把它挂到主菜单的工具菜单下），然后在Extension内指定了它的Codon为 MenuItem以及具体的ID、标签、Command类名。这样做，SharpDevelop运行的很不错，我的插件出现在了Tools菜单下。之后，我又编写了一个SharpDevelop的资源管理器（ResourceEditor）的插件类ResourceEditor.dll并把它挂到Tool菜单下。同样的，我也写了一个ResourceEditor.addin文件来对应。系统工作的很正常。 &lt;br /&gt;&lt;br /&gt;   如果我们对于每一个插件都编写这样的一个配置文件，那么插件的库文件(.dll)、插件配置文件(.addin)是一一对应的。不过这样就带来了一个小小的问题，在这样的一个以插件为基础的系统中，每一个菜单、工具栏按钮、窗体、面板都是一个插件，那么我们需要为每一个插件编写配置文件，这样就会有很多个配置文件（似乎有点太多了，不是很好管理）。SharpDevelop也想到了这个问题，于是它允许我们把多个插件的配置合并在一个插件的配置文件中。因此，我把我的两个插件库文件合并到一个Addins工程内生成了Addins.dll，又重新编写了我的插件配置文件MyAddins.addin如下： &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;AddIn name        = "MyAddins" &lt;br /&gt;       author      = "SimonLiu" &lt;br /&gt;       copyright   = "GPL" &lt;br /&gt;       url         = "http://www.icsharpcode.net" &lt;br /&gt;       description = "Display AddinTree" &lt;br /&gt;       version     = "1.0.0" &lt;br /&gt; &lt;br /&gt; Runtime &lt;br /&gt;  Import assembly="../../bin/Addins.dll"/ &lt;br /&gt; /Runtime &lt;br /&gt; &lt;br /&gt; Extension path = "/SharpDevelop/Workbench/MainMenu/Tools" &lt;br /&gt;  MenuItem id = "ResourceEditor"  &lt;br /&gt;   label = "Resource Editor"  &lt;br /&gt;   class = "Addins.ResourceEditor.Command.ResourceEditorCommand"/  &lt;br /&gt;  MenuItem id = "AddinTreeView"  &lt;br /&gt;   label = "View AddinTree"  &lt;br /&gt;   class = "Addins.AddinTreeView.AddinTreeViewCommand"/  &lt;br /&gt; /Extension  &lt;br /&gt;/AddIn &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;br /&gt;   这样，我把两个插件的功能模块使用一个插件配置文件来进行配置。同样的，我也可以把几十个功能模块合并到一个插件配置文件中。SharpDevelop把这个插件配置文件称为“Addin(插件)”，而把具体的功能模块封装为Codon，使用Command类来包装具体的功能。SharpDevelop本身的核心配置SharpDevelopCore.addin里面就包含了所有的基本菜单、工具栏、PAD的插件配置。 &lt;br /&gt;我们回过头来看一下，现在我们有了两颗树。首先，插件树本身是一个树形的结构，这个树是根据系统所有插件的各个Codon的扩展点路径构造的，表示了各个Codon在插件树中的位置，各位看官可以通过我写的这个小小的AddinTreeView来看看SharpDevelop中实际的结构。其次，插件的配置文件本身也具有了一个树形的结构，这个树结构的根节点是系统的各个插件配置文件，其下是根据这个配置文件中的Extension节点的来构成的，描述了每个Extension节点下具有的Codon。我们可以通过SharpDevelop的Tools菜单下的AddinScout来看看这个树的结构。 &lt;br /&gt;我为了试验，把SharpDevelop的插件精简了很多，构成了一个简单的小插件系统。下面是这个精简系统的两个树的截图。各位看官可以通过这两副图理解一下插件树和插件配置文件的关系（只是看同样问题的两个角度，一个是Codon的ExtensionPath，一个是配置文件的内容）。 &lt;br /&gt; &lt;br /&gt; &lt;br /&gt;总结一下SharpDevelop插件的配置文件格式。首先是 AddIn节点，需要指定AddIn的名称、作者之类的属性。其次，在AddIn节点下的Runtime节点内，使用Import …来指定本插件配置中Codon所在的库文件。如果分布在多个库文件中，可以一一指明。然后，编写具体功能模块的配置。每个功能模块的配置都以扩展点Extension开始，指定了路径(Path)属性之后，在这个节点内配置在这个扩展点下具体的Codon。每个Codon根据具体不同的实现有不同的属性。各位看官可以研究一下SharpDevelop的核心配置文件SharpDevelopCore.addin的写法，相信很容易理解的。 &lt;br /&gt;&lt;br /&gt;2、插件系统的核心AddIn和AddInTree &lt;br /&gt;   前文讲到，在SharpDevelop的Main函数中，ServiceManager.Service在InitializeServicesSubsystem方法中首次调用了AddInTreeSingleton的AddInTree实例，AddinTree在这个时候进行了初始化。现在我们就来看看AddInTreeSingleton.AddInTree到底做了些什么事情，它定义在\src\Main\Core\AddIns\AddInTreeSingleton.cs文件中。 &lt;br /&gt;&lt;br /&gt;   public static IAddInTree AddInTree  &lt;br /&gt;   { &lt;br /&gt;      get  &lt;br /&gt;      { &lt;br /&gt;         if (addInTree == null)  &lt;br /&gt;         { &lt;br /&gt;            CreateAddInTree(); &lt;br /&gt;         } &lt;br /&gt;         return addInTree; &lt;br /&gt;      } &lt;br /&gt;   } &lt;br /&gt;   AddInTreeSingleton是插件树的一个Singleton（具体的可以去看《设计模式》了），AddInTreeSingleton.AddInTree是一个属性，返回一个IAddinTree接口。这里我注意到一点，AddInTreeSingleton是从DefaultAddInTree继承下来的。既然它是一个单件模式，包含的方法全部都是静态方法，没有实例化的必要，而且外部是通过AddInTree属性来访问插件树，为什么要从DefaultAddInTree继承呢？这好像没有什么必要。这也许是重构过程中被遗漏的一个小问题吧。&lt;br /&gt;&lt;br /&gt;   我们先来看看IAddinTree接口的内容，它定义了这样的几个内容： &lt;br /&gt;      A、属性ConditionFactory ConditionFactory　返回一个构造条件的工厂类，这里的条件是指插件配置中的条件，我们以后再详细说明。 &lt;br /&gt;      B、属性CodonFactory CodonFactory　返回一个构造Codon的工厂类。 &lt;br /&gt;      C、属性AddInCollection AddIns 返回插件树的根节点Addin（插件）集合。 &lt;br /&gt;      D、方法IAddInTreeNode GetTreeNode(string path) 根据扩展点路径（path）返回对应的树节点 &lt;br /&gt;      E、方法void InsertAddIn(AddIn addIn) 根据AddIn中的扩展点路径添加一个插件到树中 &lt;br /&gt;      F、方法void RemoveAddIn(AddIn addIn) 删除一个插件 &lt;br /&gt;      G、方法Assembly LoadAssembly(string assemblyFile)  读入插件中Runtime节的Import指定的Assembly，并构造相应的CodonFactory和CodonFactory类。 &lt;br /&gt;&lt;br /&gt;   AddInTreeSingleton在首次调用AddInTree的时候会调用CreateAddInTree方法来进行初始化。CreateAddInTree方法是这样实现的： &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;addInTree = new DefaultAddInTree(); &lt;br /&gt; &lt;br /&gt;      初始化插件树为DefaultAddInTree的实例，这里我感受到了一点重构的痕迹。首先，DefaultAddInTree从名称上看是默认的插件树（既然是默认，那么换句话说还可以有其他的插件树）。但是SharpDevelop并没有给外部提供使用自定义插件树的接口（除非我们修改这里的代码），也就是说这个名称并不像它本身所暗示的那样。其次，按照Singleton通常的写法以及前面提到AddInTreeSingleton是从DefaultAddInTree继承下来的疑问，我猜想DefaultAddinTree的内容本来是在AddinTreeSingleton里面实现的，后来也许为了代码的条理性，把实现IAddinTree内容的代码剥离了出去，形成了DefaultAddinTree类。至于继承DefaultAddInTree的问题，也许这里本来是一个AddInTree的基类。这是题外话，也未加证实，各位看官可以不必放在心上（有兴趣的可以去找找以前SharpDevelop的老版本的代码来看看）。 &lt;br /&gt;这里有两个察看代码的线路，一个是DefaultAddInTree的构造函数的代码，在这个构造函数中构造了Codon和Condtion的工厂类。另外一个是CreateAddInTree后面的代码，搜索插件文件，并根据插件文件进行AddIn的构造。各位看官可以选择走分支线路，也可以选择先看主线（不过这样你会漏掉不少内容）。 &lt;br /&gt;&lt;br /&gt;2.1 支线 （DefaultAddInTree的构造函数） &lt;br /&gt;   我们把CreateAddInTree的代码中断一下压栈先，跳到DefaultAddInTree的构造函数中去看一看。DefaultAddInTree定义在\src\Main\Core\AddIns\DefaultAddInTree.cs文件中。在DefaultAddInTree的构造函数中，注意到它具有一个修饰符internal，也就是说这个类只允许Core这个程序集中的类对DefaultAddInTree进行实例化（真狠啊）。构造函数中的代码只有一句： &lt;br /&gt;&lt;br /&gt; LoadCodonsAndConditions(Assembly.GetExecutingAssembly()); &lt;br /&gt;   虽然只有一行代码，不过这里所包含的内容却很精巧，是全局的关键，要讲清楚我可有得写了。首先，通过全局的Assembly对象取得入口程序的Assembly，传入LoadCodonsAndConditions方法中。在该方法中，枚举传入的Assembly中的所有数据类型。如果不是抽象的，并且是AbstractCodon的子类，并且具有对应的CodonNameAttribute属性信息，那么就根据这个类的名称建立一个对应的CodonBuilder并它加入CodonFactory中（之后对Condition也进行了同样的操作，我们专注来看Codon部分，Condition跟Codon基本上是一样的）。 &lt;br /&gt;   这里的CodonFactory类和CodonBuilder类构成了SharpDevelop插件系统灵活的基础，各位看官可要看仔细了。 &lt;br /&gt;   我们以实例来演示，以前文我编写的AddinTreeViewCommand为例。在入口的Assembly中会搜索到MenuItemCodon，它是AbstractCodon的一个子类、包装MenuItem(菜单项)Command（命令）的Codon。符合条件，执行 &lt;br /&gt;&lt;br /&gt;codonFactory.AddCodonBuilder(new CodonBuilder(type.FullName, assembly)); &lt;br /&gt;   首先根据类名MenuItemCodon和assembly 构造CodonBuilder。CodonBuilder定义在\src\Main\Core\AddIns\Codons\CodonBuilder.cs文件中。在CodonBuilder的构造函数中根据MenuItemCodon的CodonNameAttribute属性信息取得该Codon的名称MenuItem。CodonNameAttribute描述了Codon的名称，这个MenuItem也就是在.addin配置文件中对应的MenuItem标签，后文会看到它的重要用途。在CodonBuilder中除了包含了该Codon的ClassName（类名）和CodonName属性之外，就只有一个方法BuildCodon了。&lt;br /&gt;&lt;br /&gt;  public ICodon BuildCodon(AddIn addIn) &lt;br /&gt;  { &lt;br /&gt;   ICodon codon; &lt;br /&gt;   try { &lt;br /&gt;    // create instance (ignore case) &lt;br /&gt;    codon = (ICodon)assembly.CreateInstance(ClassName, true); &lt;br /&gt;     &lt;br /&gt;    // set default values &lt;br /&gt;    codon.AddIn = addIn; &lt;br /&gt;   } catch (Exception) { &lt;br /&gt;    codon = null; &lt;br /&gt;   } &lt;br /&gt;   return codon; &lt;br /&gt;  } &lt;br /&gt;&lt;br /&gt;   很明显，BuildCodon根据构造函数中传入的assembly和类型的ClassName，建立了具体的Codon的实例，并和具体的AddIn关联起来。 &lt;br /&gt;   之后，codonFactory调用AddCodonBuilder方法把这个CodonBuilder加入它的Builder集合中。我们向上一层，看看codonFactory如何使用这个CodonBuilder。 &lt;br /&gt;   在文件\src\Main\Core\AddIns\Codons\CodonFactory.cs中，codonFactory只有两个方法。AddCodonBuilder方法把CodonBuilder加入一个以CodonName为索引的Hashtable中。另外一个方法很重要： &lt;br /&gt;&lt;br /&gt;  public ICodon CreateCodon(AddIn addIn, XmlNode codonNode) &lt;br /&gt;  { &lt;br /&gt;   CodonBuilder builder = codonHashtable[codonNode.Name] as CodonBuilder; &lt;br /&gt;    &lt;br /&gt;   if (builder != null) { &lt;br /&gt;    return builder.BuildCodon(addIn); &lt;br /&gt;   } &lt;br /&gt;    &lt;br /&gt;   throw new CodonNotFoundException(String.Format("no codon builder found for {0}", codonNode.Name)); &lt;br /&gt;  } &lt;br /&gt; &lt;br /&gt;   在这里，addin是这个配置文件的描述（也就是插件），而这个XmlNode类型的CodonNode是什么东西？ &lt;br /&gt;   还记得配置文件中在Extension标签下的Class、MenuItem、Pad之类的标签吗？我曾经说过，这些就是Codon的描述，现在我们来看看到底是不是如此。以前文的AddinTreeView配置为例： &lt;br /&gt;&lt;br /&gt; Extension path = "/SharpDevelop/Workbench/MainMenu/Tools" &lt;br /&gt;  MenuItem id = "AddinTreeView"  &lt;br /&gt;   label = "View AddinTree"  &lt;br /&gt;   class = "Addins.AddinTreeView.AddinTreeViewCommand"/  &lt;br /&gt; /Extension  &lt;br /&gt; &lt;br /&gt;   SharpDevelop在读入插件配置文件的Extension标签之后，就把它的ChildNodes（XmlElement的属性）依次传入CodonFactory的CreateCodon方法中。这里它的ChildNodes[0]就是这里的MenuItem id = ..... /节点，也就是codonNode参数了。这个XML节点的Name是MenuItem，因此CreateCodon的第一行&lt;br /&gt;&lt;br /&gt;CodonBuilder builder = codonHashtable[codonNode.Name] as CodonBuilder; &lt;br /&gt; &lt;br /&gt;   根据节点的名称(MenuItem)查找对应的CodonBuilder。记得前面的CodonBuilder根据CodonNameAttribute取得了MenuItemCodon的CodonName吗？就是这个MenuItem了。CodonFactory找到了对应的MenuItemCodon的CodonBuilder（这个是在DefaultAddInTree的构造函数中调用LoadCodonsAndConditions方法建立并加入CodonFactory中的，还记得么？），之后使用这个CodonBuilder建立了对应的Codon，并把它返回给调用者。 &lt
