<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>中文 &#187; 并行计算</title>
	<atom:link href="http://software.intel.com/zh-cn/blogs/category/parallel/feed/" rel="self" type="application/rss+xml" />
	<link>http://software.intel.com/zh-cn/blogs</link>
	<description></description>
	<lastBuildDate>Mon, 06 Feb 2012 03:24:52 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.3</generator>
		<item>
		<title>VTune(TM) Amplifier XE 报告输出gprof的格式</title>
		<link>http://software.intel.com/zh-cn/blogs/2012/01/20/vtunetm-amplifier-xe-gprof/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2012/01/20/vtunetm-amplifier-xe-gprof/#comments</comments>
		<pubDate>Fri, 20 Jan 2012 08:09:03 +0000</pubDate>
		<dc:creator>Peter Wang (Intel)</dc:creator>
				<category><![CDATA[并行计算]]></category>
		<category><![CDATA[英特尔® 软件网络 2.0]]></category>
		<category><![CDATA[VTune gprof format]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2012/01/20/vtunetm-amplifier-xe-gprof/</guid>
		<description><![CDATA[使用VTune的小技巧。]]></description>
			<content:encoded><![CDATA[<p>在VTune（TM）Amplifier XE 2011 中包含二类预定义的分析：</p>
<p>1. User-mode Sampling and Tracing Analysis：</p>
<p>热点分析(Hotspots Analysis)，并行分析(Concurrency Analysis)，锁和等待分析(Locks and Waits Analysis)</p>
<p>2. Hardware event-based sampling analysis</p>
<p>一般性研究（General Exploration），内存带宽（Bandwidth），访问冲突（Access Contention），分支预测（Branch Analysis），存储访问（Memory Access），端口饱和（Port Saturation），等。</p>
<p>用户可以在amplxe-gui（图形界面）使用上述预定义的分析类型，结果产生在响应的报告。</p>
<p>当然用户也可以使用命令行（参阅<a href="http://software.intel.com/zh-cn/blogs/2010/11/10/amplxe-cl/">此文</a>）收集性能，结果也可以在命令行输出或导入工具的图形界面。使用命令行的好处是用户可以自定义自己的分析类型，如：</p>
<ol>
<li>热点分析中，自定义采样间隔，参阅<a href="http://software.intel.com/en-us/articles/cannot-use-user-defined-hotspots-in-command-line">此文</a></li>
<li>自选的CPU事件计数器，参阅<a href="http://software.intel.com/en-us/articles/event-configuration-from-the-command-line/">此文</a> </li>
</ol>
<p>VTune™ Amplifier XE 定义了多种自己的输出格式，可以显示在工具的图形界面上。除此之外，工具还支持了gprof的输出格式。此种格式仅可以在命令行输出，<strong>不可以在图形界面上输出</strong>。</p>
<p>请看下面例子：</p>
<p>VTune的输出格式列出最热函数，而不是全部；gprof格式给出全部函数（即使占用CPU时间极少），且注重函数间调用关系</p>
<pre name="code" class="cpp:showcolumns">
<pre name="code" class="shell:nogutter:collapse">
<pre name="code" class="shell"># amplxe-cl -collect-with runss -knob interval=8 -knob collectSamplesMode=stack -- ./primes.icc
Determining primes from 1 - 100000
Found 9592 primes
Using result path `/home/peter/problem_report/r000runss'
Executing actions 75 % Generating a report
Summary
-------

Elapsed Time:  0.883
CPU Time:      2.080
Executing actions 100 % done               

# amplxe-cl -report hotspots
Using result path `/home/peter/problem_report/r000runss'
Executing actions 75 % Generating a report
Function    Module      CPU Time
----------  ----------  --------
findPrimes  primes.icc  2.080
Executing actions 100 % done                                                   

# amplxe-cl -report gprof-cc
Using result path `/home/peter/problem_report/r000runss'
Executing actions 75 % Generating a report
Index  % CPU Time:Total  CPU Time:Self  Children  Name           Index
-----  ----------------  -------------  --------  -------------  -----
[0]    100.0             0.0            2.08      clone          [0]
                         0              2.080      start_thread  [1]

                         0              2.080      clone         [0]
[1]    100.0             0.0            2.08      start_thread   [1]
                         2.080          2.080      findPrimes    [2]

                         2.080          2.080      start_thread  [1]
[2]    100.0             2.08           0.0       findPrimes     [2]

[3]    0.0               0.0            0.0       _start         [3]
                         0              0          main          [4]

                         0              0          _start        [3]
[4]    0.0               0.0            0.0       main           [4]

Index by function name

Index  Function
-----  ------------
[3]    _start
[0]    clone
[2]    findPrimes
[4]    main
[1]    start_thread
Executing actions 100 % done</pre>
</pre>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2012/01/20/vtunetm-amplifier-xe-gprof/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Delphi 多线程知识</title>
		<link>http://software.intel.com/zh-cn/blogs/2012/01/13/delphi-2/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2012/01/13/delphi-2/#comments</comments>
		<pubDate>Fri, 13 Jan 2012 08:32:11 +0000</pubDate>
		<dc:creator>formiss</dc:creator>
				<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[并行计算]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2012/01/13/delphi-2/</guid>
		<description><![CDATA[1-1 多线程的基本概念 WIN 98/NT/2000/XP 是个多任务操作系统，也就是：一个进程可以划分为多个线程，每个线程轮流占用CPU 运行时间和资源，或者说，把CPU 时间划成片，每个片分给不同的线程，这样，每个线程轮流的“挂起”和“唤醒”，由于时间片很小，给人的感觉是同时运行的。 多线程带来如下好处：（自己阅读） 1）避免瓶颈； 2）并行操作； 3）提高效率； 在多线程中，通过优先级管理，可以使重要的程序优先操作，提高了任务管理的灵活性。 另一方面，在多CPU 系统中，可以把不同的线程在不同的CPU 中执行，真正做到同时处理多任务（Win 98 只是模拟的，而Win/NT/2000是真正的多CPU同时操作）。 多线程的两个概念： 1）进程：也称任务，程序载入内存，并分配资源，称为“一个进程”。 注意：进程本身并不一定要正在执行。进程由以下几部分组成： a&#62;一个私有的地址空间，它是进程可以使用的一组虚拟内存地址空间； b&#62;程序的相关代码、数据源； c&#62;系统资源，比如操作系统同步对象等； d&#62;至少包含一个线程（主线程）； 2）线程：是程序的执行单位（线程本身并不包括程序代码，真正拥有代码的是进程），每个进程至少包括一个线程，称为主线程，一个进程如果有多个线程，就可以共享同一进程的资源，并可以并发执行。 线程是进程的一个执行单元，是操作系统分配CPU 时间的基本实体，线程主要由如下两部分组成： a&#62;数据结构； b&#62;CPU 寄存器和堆栈； 一个进程中的线程，可以独立运行，也可以控制另一个线程的运行。 请注意： 多线程不能滥用，书上提到了多线程的几个缺点（自阅）。 1-2 Tthread 对象 虽然Windows 提供了比较多的多线程设计的API 函数，但是直接使用API 函数一方面极其不方便，而且使用不当还容易出错。为解决这个问题，Borland 公司率先推出了一种Tthread 对象，来解决多线程设计上的困难，简化了多线程问题的处理。 应该注意，Tthread 对象是没有实例的，它和界面的交流，主要依靠主窗体（主VCL线程），这和其他对象使用上有些区别。 一、Tthread 对象的主要方法 构造线程： constructor Create(CreateSuspended:boolean) 其中：CreateSuspended=true 构造但不唤醒 false 构造的同时即唤醒 也可以用如下方法 inheried [...]]]></description>
			<content:encoded><![CDATA[<p>1-1 多线程的基本概念</p>
<p>WIN 98/NT/2000/XP 是个多任务操作系统，也就是：一个进程可以划分为多个线程，每个线程轮流占用CPU 运行时间和资源，或者说，把CPU 时间划成片，每个片分给不同的线程，这样，每个线程轮流的“挂起”和“唤醒”，由于时间片很小，给人的感觉是同时运行的。<br />
多线程带来如下好处：（自己阅读）<br />
1）避免瓶颈；<br />
2）并行操作；<br />
3）提高效率；<br />
在多线程中，通过优先级管理，可以使重要的程序优先操作，提高了任务管理的灵活性。<br />
另一方面，在多CPU 系统中，可以把不同的线程在不同的CPU 中执行，真正做到同时处理多任务（Win 98 只是模拟的，而Win/NT/2000是真正的多CPU同时操作）。</p>
<p>多线程的两个概念：</p>
<p>1）进程：也称任务，程序载入内存，并分配资源，称为“一个进程”。<br />
注意：进程本身并不一定要正在执行。进程由以下几部分组成：<br />
a&gt;一个私有的地址空间，它是进程可以使用的一组虚拟内存地址空间；<br />
b&gt;程序的相关代码、数据源；<br />
c&gt;系统资源，比如操作系统同步对象等；<br />
d&gt;至少包含一个线程（主线程）；</p>
<p>2）线程：是程序的执行单位（线程本身并不包括程序代码，真正拥有代码的是进程），每个进程至少包括一个线程，称为主线程，一个进程如果有多个线程，就可以共享同一进程的资源，并可以并发执行。<br />
线程是进程的一个执行单元，是操作系统分配CPU 时间的基本实体，线程主要由如下两部分组成：<br />
a&gt;数据结构；<br />
b&gt;CPU 寄存器和堆栈；<br />
一个进程中的线程，可以独立运行，也可以控制另一个线程的运行。</p>
<p>请注意：<br />
多线程不能滥用，书上提到了多线程的几个缺点（自阅）。</p>
<p>1-2 Tthread 对象</p>
<p>虽然Windows 提供了比较多的多线程设计的API 函数，但是直接使用API 函数一方面极其不方便，而且使用不当还容易出错。为解决这个问题，Borland 公司率先推出了一种Tthread 对象，来解决多线程设计上的困难，简化了多线程问题的处理。<br />
应该注意，Tthread 对象是没有实例的，它和界面的交流，主要依靠主窗体（主VCL线程），这和其他对象使用上有些区别。</p>
<p>一、Tthread 对象的主要方法</p>
<p>构造线程：</p>
<p>constructor Create(CreateSuspended:boolean)</p>
<p>其中：CreateSuspended=true 构造但不唤醒<br />
false 构造的同时即唤醒</p>
<p>也可以用如下方法</p>
<p>inheried Create(CreateSuspended:boolean)</p>
<p>挂起线程：</p>
<p>suspend</p>
<p>（把线程挂起的次数加一）</p>
<p>唤醒线程：</p>
<p>resume</p>
<p>（注意：注意这个属性是把线程挂起的次数减一，当次数为0 时，即唤醒。也就是说，线程挂起多少次，唤醒也需要多少次。同时挂起的时候将保持线程的地址指针不变，所以线程挂起后再唤醒，将从挂起的地方开始运行）</p>
<p>析构（清除线程所占用的内存）：</p>
<p>destroy</p>
<p>终止线程（后面会具体讨论）:</p>
<p>Terminate</p>
<p>二、线程应用的简单例子：</p>
<p>下面通过一个例子说明上述方法的应用。我们知道，循环是独占性最强的运行方式之一，现在希望建立两个线程对象，实现循环的并行运行。具体方法如下：</p>
<p>File---New---Thread Object</p>
<p>这就自动在主Form中建立了一个线程单元（在对话框里写上线程名字），默认的名字是Unit2。同样方法建立第二个线程单元Unit3。</p>
<p>要注意的是：Unit2和Unit3中有一个给定的过程：</p>
<p>procedure Object.Execute;<br />
begin</p>
<p>end;</p>
<p>其中的程序是线程唤醒后自动执行的程序，也可以在里面调用其他自定义的过程和函数。这个过程的结束，意味着线程程序的结束。<br />
为了构造线程，在interface的Type区，定义一个构造过程：</p>
<p>type<br />
Object = class(TThread) //自动给出的，也可以直接改</p>
<p>private</p>
<p>protected</p>
<p>procedure Execute; override;</p>
<p>public<br />
constructor create; //自己写的</p>
<p>并且在implementation区域写上：</p>
<p>constructor Object.create;<br />
begin<br />
inherited create(true);<br />
end</p>
<p>其中Object 为线程对象的名字。所以这么写，是希望在主Form中调用这个构造过程。<br />
Create()的参数用True，表明构造出的线程为挂起状态。<br />
注意一下，在同一个线程对象里，如果两次构造，将产生两个独立的线程，不但运行是独立的，而且使用线程的局部变量也是独立的。但这里为了简化问题，还是建立了两个独立的线程对象，而且两个循环数<br />
是不同的，在并行运算时容易判断出是两个不同的程序在运行。</p>
<p>假定我们给两个线程对象起的名字是：</p>
<p>mymath1<br />
mymath2</p>
<p>这样在Unit1，应该作如下声明：</p>
<p>implementation</p>
<p>{$R *.DFM}</p>
<p>uses unit2,unit3;</p>
<p>var thread1:mymath1;<br />
thread2:mymath2;</p>
<p>这样在主线程，将可以通过这两个线程变量调用对应的线程方法。</p>
<p>在主线程区构造线程的方法是：</p>
<p>thread1:=mymath1.create;<br />
thread2:=mymath2.create;</p>
<p>挂起：</p>
<p>thread1.suspend;<br />
thread2.suspend;</p>
<p>唤醒：</p>
<p>thread1.resume;<br />
thread2.resume;</p>
<p>析构：</p>
<p>thread1.destroy;<br />
thread2.destroy;</p>
<p>这里需要说明的是，由于线程单元需要调用Form的Edit控件（对象），可以采用两种方法：</p>
<p>1）在线程单元定义一个TEdit对象，例如</p>
<p>edit4:Tedit;</p>
<p>在Execute过程内直接引用</p>
<p>但在Unit1中一定要在FormCreate过程里作一个赋值：</p>
<p>procedure TForm1.FormCreate(Sender: TObject);<br />
begin<br />
thread1.edit4:=edit1;<br />
end;</p>
<p>这样，就把第一线程的edit4与Form上的edit1联系来。</p>
<p>2）在第二个线程中首先声明调用Unti1，也就是要加上<br />
Uses Unit1;</p>
<p>这样就可以在该线程单元直接调用主Form的控件了，比如在Unit3中可以写：</p>
<p>form1.edit2.text:=inttostr(i)</p>
<p>了解了这些基本规则，就可以写出比较复杂的多线程程序了。<br />
还有一点要说明的，默认生成的线程单元，调用的单元只有一个：</p>
<p>Uses Classes;</p>
<p>这样，往往很多函数和对象在线程单元里不能使用，所以在必要时，应该根据需要User相应的单元，这个例程为了简单，把大部分常用的单元都拷过去了，这并不是推荐的办法，因为这样一来会使程序的垃圾过<br />
多，所以，一般要用什么拷什么。</p>
<p>三、常用的API 函数</p>
<p>在处理多线程问题的时候,也经常用到Windows提供的API 函数，需要说明的是，Tthread 对象内部封装的方法，其实主要也是调用API 函数，但是，考虑更全面，更安全。而直接调用API 函数，往往会因为运用不当，出现一些不应有的错误。所以，我个人以为，只要用Tthread 对象的方法能解决的，就不要直接调用API 函数，API 函数只应该在用在Tthread 对象方法解决不了的时候。<br />
例如Tthread 对象方法内部调用API 函数的时候，一般使用推荐的默认值，但需要更精细的控制时，就可以直接使用API 函数。<br />
其实，Tthread 对象方法已经受到了大多数程序设计者的认可，比如，原来VB是不具备直接处理多线程的能力的，但是，现在VB.Net就宣称，它具备了简单处理多线程问题的能力，这就很说明问题。<br />
下面简单介绍几种API 函数，为了清晰方便，这里着重在于说明，函数正确的描述可以自己阅读书上的例子和手册：<br />
构建线程：</p>
<p>CreateThread(参数1，--安全属性（一般=Nil，默认安全属性）</p>
<p>参数2，--线程堆栈尺寸（一般=0，与主线程相同长度，而且可以根据需要自动变化）<br />
参数3，--指向函数名指针，@函数名，这个参数十分重要，不正确将无法调用成功。<br />
参数4，--用户需要向线程传递的参数，是一个指向结构的指针，不需传递参数时，为Nil。<br />
参数5）--传入与线程有关的一些参数，例如：<br />
CREATE_SUSPENDED 创建一个挂起的线程；<br />
0 创建后立即激活。</p>
<p>书上有这个函数应用的十分清晰的例子，可以自己阅读。<br />
一般并不推荐使用 CreateTheard函数，而推荐使用RTL 库里的System单元中定义的 BeginTheard函数，因为这除了能创建一个线程和一个入口函数以外，还增加了几项保护措施，具体的请参阅书上的第10页说明。</p>
<p>对应suspend（挂起）和resume（唤醒）的两个API 函数为：</p>
<p>Function SuspendThread(hThread:Thandle):DWORD;</p>
<p>Function ResumeThread（hThread:Thandle):DWORD;</p>
<p>其中，Thandle被要求控制线程的句柄，函数调用成功，返回挂起的次数，调用不成功。则返回0xFFFFFFFF。</p>
<p>四、线程的终止和退出：</p>
<p>1)自动退出：</p>
<p>一个线程从Execute()过程中退出，即意味着线程的终止，此时将调用Windows的ExitThread()函数来清除线程所占用的堆栈。<br />
如果线程对象的 FreeOnTerminate 属性设为True，则线程对象将自动删除，并释放线程所占用的资源。<br />
这是消除线程对象最简单的办法。</p>
<p>2)受控退出：</p>
<p>利用线程对象的Terminate属性，可以由进程或者由其他线程控制线程的退出。只需要简单的调用该线程的Terminate方法，并设直线程对象的Terminate属性为True。<br />
在线程中，应该不断监视Terminate的值，一旦发现为True，则退出，例如在Execute()过程中可以这样写：</p>
<p>While not Terminate do<br />
begin<br />
........<br />
end;</p>
<p>3)退出的API 函数：</p>
<p>关于线程退出的API 函数声明如下：code</p>
<p>Function TerminateThread(hThread:Thandle;dwExitCode:DWORD);</p>
<p>不过，这个函数会使代码立刻终止，而不管程序中有没有</p>
<p>try....finally</p>
<p>机制，可能会导致错误，不到万不得已，最好不要使用。</p>
<p>4) 利用挂起线程的方法（suspend）</p>
<p>利用挂起线程的suspend方法，后面跟个Free，也可以释放线程，<br />
例如：</p>
<p>thread1.suspend; //挂起<br />
thread2.free; //释放</p>
<p>书上有相应的例子。</p>
<p>五、线程的优先级：</p>
<p>在多线程的情况下，一般要根据线程执行任务的重要性，给线程适当的优先级，一般如果量的线程同时申请CPU 时间，优先级高的线程优先。</p>
<p>在Windows下，给线程的优先级分为30级，而Delphi中Tthread 对象相对简单的把优先级分为七级。也就是在Tthread中声明了一个枚举类型TTthreadPriority:</p>
<p>type</p>
<p>TTthreadPriority(tpidle,tpLowest,tpLower,tpNormal,<br />
tpHight,tpHighest,tpTimecrital)</p>
<p>分别对应的是最低（系统空闲时有效，-15），较低（-2），低（-1），正常（普通0），高（1），较高（2），最高（15）。</p>
<p>其中tpidle和tpTimecrital有些特殊，具体情况请阅读书上有关内容。</p>
<p>设置优先级可使用thread对象的priority属性：</p>
<p>threadObject.priority:=Tthreadpriority(级别);</p>
<p>这里给出了一个演示多线程优先级的实例：</p>
<p>1-3 在数据库中使用多线程</p>
<p>一）使用ADO模式</p>
<p>由于Delphi 6.0的ADO 数据源控件内置了多线程能力，所以，在ADO模式下，使用多线程不需要做更多的工作。用两个ADOTable控件，分别连到两个数据库，并且分别通过DataSource控件，与数据帮定控件联系就可以了，这样就可以实现前后台处理数据库问题。</p>
<p>二）使用BDE模式和Tseeion对象</p>
<p>如果需要使用BDE 模式，那么多线程使用数据库，就要考虑Session的问题。在单线程时，每个数据源的建立就自动生成一个Session，这是这个数据源私有的关于数据库信息的文件。但多线程时，必须统一管理，所以在BDE 中专门提供了一个Tsession对象，它可以同时管理不同的Databas数据源对象。<br />
Databas数据源可以接受来自不同数据平台的数据库。</p>
<p>数据库1---databas(2)----table(Qurey)(3)---datasource<br />
| |<br />
| |<br />
|--------- Tsession(1)<br />
| |<br />
| |<br />
数据库2---databas(2)----table(Qurey)(3)---datasource</p>
<p>方法：<br />
1）Tsession<br />
属性：SessionName=名（自起）<br />
Active=true （激活）<br />
2）Database（可以有多个）<br />
属性：SessionName=Tsession名<br />
Dataname=名（自起，作为Table的标识）<br />
AliasName=数据库别名<br />
Connected=True （激活）<br />
3）Table或Qurey<br />
属性：SessionName=Tsession名（不要用默认值）<br />
DatabaseName=如果前面起了名，这里就会出现Database<br />
的名字。<br />
Tablename=表名<br />
Active=true （激活）<br />
以后比如加入Datasoucre和其他一样，这样就可以构造两个前后台处理的数据库管理系统了。</p>
<p>2-4 多线程的同步机制</p>
<p>同步机制，实际上是事件驱动机制，意思是让线程平时处于“休眠”状态，除非发生某个事件才触发。<br />
例如一个拷贝文件，拷贝线程完成一个程序块后，再唤醒进程条线程做一个格的填充。<br />
研究多线程的同步机制的必要性在于，多线程同步工作时，如果同时调用相同的资源，就可能会出现问题，一般读出是不会有问题的，但是，如果写入（全局变量、数据库），就会发生冲突，甚至产生死<br />
锁和竞争问题。</p>
<p>一、使用Synchronize方法</p>
<p>这个方法用于访问VCL 主线程所管理的资源，其方法的应用是：<br />
第一步：把访问主窗口（或主窗口控件资源）的代码放到线程的一个方法中；<br />
第二步：是在线程对象的Execute方法中，通过Synchronize方法使用该方法。<br />
实例：<br />
procedure Theater.Execute;<br />
begin<br />
Synchronize(update);<br />
end;</p>
<p>procedure Theater.update;<br />
begin<br />
.........<br />
end;</p>
<p>这里通过 Synchronize使线程方法update同步。</p>
<p>二、使用VCL类的Look方法</p>
<p>在Delphi的IDE提供的构件中，有一些对象内部提供了线程的同步机制，工作线程可以直接使用这些控件，比如：Tfont，Tpen，TBitmap，TMetafile，Ticon等。另外，一个很重要的控件对象叫TCanvas，提供了一个Lock方法用于线程的同步，当一个线程使用此控件对象的时候，首先调用这个对象的Lock方法，然后对这个控件进行操作，完毕后再调用Unlock方法，释放对控间的控制权。<br />
例如：<br />
CanversObject.look;<br />
try<br />
画图<br />
finally<br />
CanversObject.unlock;<br />
end;<br />
{使用这个保护机制,保证不论有没有异常，unlock都会被执行否则很可能会发生死锁。在多线程设计的时候，应该很注意发生死锁的问题}</p>
<p>三、Waitfor方法<br />
当一个线程应该等待另一个线程结束时，可以调用Waitfor方法。这个方法属于等待线程对象，Waitfor方法的原型如下:</p>
<p>Function Waitfor(Const Astring:string):string;</p>
<p>比如在前面最基本的线程的例子中，唤醒线程的语句中加上</p>
<p>thread1.resume;<br />
thread1.waitfor;<br />
thread2.resume;</p>
<p>那么所有的线程都必须等待thread1运行完毕后才能运行，其中包括主线程，可以预想，由于thread1调用了主窗体的Edit控件，那么，在thread1运行中间，Edie1也不会显示。<br />
这就告诉我们，这样的代码是不能作为主线程的一部分的，如果与主窗体连接的线程内等待另一个线程结束，而另一个线程又要等待访问用户界面，就可能是程序陷于死锁。<br />
这点在应用的时候要谨慎。</p>
<p>四、利用Windows的API 实现同步</p>
<p>Windows API函数提供了很多同步技术，下面简要介绍。</p>
<p>1）临界区</p>
<p>使用线程的时候，遇到的一个基本的问题，就是多个线程访问同一个对象，比如访问相同的文件、DLL、相同的通讯资源，特别是数据库的访问，当多个线程对同一数据库字段写入的时候，其结果会出<br />
现不确定性。<br />
临界区用于解决这个问题，它可以保证线程使用敏感数据的时候，阻赛其他的线程访问名干数据，使用时首先要初始化，其声明一个TRTLCriticalSection类型的变量：</p>
<p>var<br />
CS:TRTLCriticalSection;</p>
<p>初始化：</p>
<p>initializeCriticalSection(cs);</p>
<p>独占</p>
<p>EnterCriticalSection(cs);</p>
<p>解除独占</p>
<p>LeaveCriticalSection(CS);</p>
<p>使用临界区是比较方便而且概念比较清晰的的线程同步机制，应用比较广泛。<br />
请注意，临界区只能在一个进程内使用，首先要标记出把数据作为临界区操作的那些代码，在这部分代码执行前，计算机首先要查看一下全局记录，已确定是否有其它线程在临界区中，同时也要查看这个临界区是否和第一个临界区相关，也就是说同一个程序中可能会有几个不同的临界区，然后计算机再决定运行策略。</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2012/01/13/delphi-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>利用Windows API 多线程编程解决“哲学家进餐问题”</title>
		<link>http://software.intel.com/zh-cn/blogs/2012/01/13/windows-api/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2012/01/13/windows-api/#comments</comments>
		<pubDate>Fri, 13 Jan 2012 08:28:59 +0000</pubDate>
		<dc:creator>wgj200123</dc:creator>
				<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[并行计算]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2012/01/13/windows-api/</guid>
		<description><![CDATA[哲学家进餐问题描述： 有五个哲学家，他们的生活方式是交替地进行思考和进餐。哲学家们公用一张圆桌，周围放有五把椅子，每人坐一把。在圆桌上有五个碗和五根筷子，当一个哲学家思考时，他不与其他人交谈，饥饿时便试图取用其左、右最靠近他的筷子，但他可能一根都拿不到。只有在他拿到两根筷子时，方能进餐，进餐完后，放下筷子又继续思考。 01.#include 02.#include 03. 04.#define P(S) WaitForSingleObject(S, INFINITE) //P操作 05.#define V(S) ReleaseSemaphore(S, 1, NULL) 06.#define NUMBERS 5 //叉子个数 07.typedef HANDLE Semaphore; //信号量原型 08.Semaphore chopstick[5]; 09.Semaphore mutex; //定义一个互斥量 10.Semaphore room; 11.char *philosophers[5] = {"哲学家1 ", "哲学家2 ", "哲学家3 ", "哲学家4 ", "哲学家5 "}; 12.char *str[] = {"得到左手边的筷子", "得到右手边的筷子", "得到一双筷子，开始吃饭!", "饭吃完了，该开始思考问题了"}; 13. 14.DWORD WINAPI philosopher(LPVOID lParam); [...]]]></description>
			<content:encoded><![CDATA[<p>哲学家进餐问题描述：</p>
<p>有五个哲学家，他们的生活方式是交替地进行思考和进餐。哲学家们公用一张圆桌，周围放有五把椅子，每人坐一把。在圆桌上有五个碗和五根筷子，当一个哲学家思考时，他不与其他人交谈，饥饿时便试图取用其左、右最靠近他的筷子，但他可能一根都拿不到。只有在他拿到两根筷子时，方能进餐，进餐完后，放下筷子又继续思考。</p>
<p>01.#include<br />
02.#include<br />
03.<br />
04.#define P(S) WaitForSingleObject(S, INFINITE) //P操作<br />
05.#define V(S) ReleaseSemaphore(S, 1, NULL)<br />
06.#define NUMBERS 5 //叉子个数<br />
07.typedef HANDLE Semaphore; //信号量原型<br />
08.Semaphore chopstick[5];<br />
09.Semaphore mutex; //定义一个互斥量<br />
10.Semaphore room;<br />
11.char *philosophers[5] = {"哲学家1 ", "哲学家2 ", "哲学家3 ", "哲学家4 ", "哲学家5 "};<br />
12.char *str[] = {"得到左手边的筷子", "得到右手边的筷子", "得到一双筷子，开始吃饭!", "饭吃完了，该开始思考问题了"};<br />
13.<br />
14.DWORD WINAPI philosopher(LPVOID lParam); //线程函数声明<br />
15.void main()<br />
16.{<br />
17. HANDLE hThread[NUMBERS]; //线程句柄<br />
18. DWORD ThreadID[NUMBERS]; //线程ID<br />
19.<br />
20. //初始化信号量<br />
21. mutex = CreateSemaphore(NULL, 1, 1, "mutex");<br />
22. if(!mutex)<br />
23. cout&lt;&lt;"创建信号量失败"&lt;&lt;endl;<br />
24. for (int i=0; i&lt;5; i++)<br />
25. {<br />
26. chopstick[i] = CreateSemaphore(NULL, 1, 1, NULL);<br />
27. if(!chopstick[i])<br />
28. cout&lt;&lt;"创建信号量失败"&lt;&lt;endl;<br />
29. }<br />
30. for (i=0; i&lt;NUMBERS; i++)<br />
31. {<br />
32. hThread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)philosopher, (LPVOID *)&amp;i, 0, &amp;ThreadID[i]);<br />
33. if (!hThread[i])<br />
34. {<br />
35. cout&lt;&lt;"创建线程失败"&lt;&lt;endl;<br />
36. }<br />
37. WaitForSingleObject(hThread[i], 5000);<br />
38. }<br />
39.}<br />
40.<br />
41.DWORD WINAPI philosopher(LPVOID lParam)<br />
42.{<br />
43. int i = *(int *)lParam;<br />
44. while (true)<br />
45. {<br />
46. P(mutex);<br />
47. P(chopstick[i]);<br />
48. cout&lt;&lt;philosophers[i]&lt;&lt;str[0]&lt;&lt;endl;<br />
49. P(chopstick[(i+1)%5]);<br />
50. cout&lt;&lt;philosophers[i]&lt;&lt;str[1]&lt;&lt;endl;<br />
51. cout&lt;&lt;philosophers[i]&lt;&lt;str[2]&lt;&lt;endl;<br />
52. V(chopstick[i]);<br />
53. V(chopstick[(i+1)%5]);<br />
54. cout&lt;&lt;philosophers[i]&lt;&lt;str[3]&lt;&lt;endl&lt;&lt;endl;<br />
55. Sleep(1000); //整个吃饭过程大约一秒时间<br />
56. V(mutex);<br />
57. }<br />
58. return 0;<br />
59.}</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2012/01/13/windows-api/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HTML5之Web Storage</title>
		<link>http://software.intel.com/zh-cn/blogs/2011/12/26/html5web-storage/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2011/12/26/html5web-storage/#comments</comments>
		<pubDate>Mon, 26 Dec 2011 04:00:27 +0000</pubDate>
		<dc:creator>章政</dc:creator>
				<category><![CDATA[Android 开发]]></category>
		<category><![CDATA[Blog Challenge]]></category>
		<category><![CDATA[全国博客大奖赛]]></category>
		<category><![CDATA[全国大学生软件创新大赛专栏]]></category>
		<category><![CDATA[其他]]></category>
		<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[图形和视觉计算]]></category>
		<category><![CDATA[并行计算]]></category>
		<category><![CDATA[开放源代码]]></category>
		<category><![CDATA[服务器]]></category>
		<category><![CDATA[游戏]]></category>
		<category><![CDATA[移动技术]]></category>
		<category><![CDATA[英特尔® 软件网络 2.0]]></category>
		<category><![CDATA[英特尔信息技术峰会]]></category>
		<category><![CDATA[虚拟化技术]]></category>
		<category><![CDATA[软件开发工具]]></category>
		<category><![CDATA[软件技术学习及认证]]></category>
		<category><![CDATA[高校博客大奖赛]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2011/12/26/html5web-storage/</guid>
		<description><![CDATA[WebStorage的出现是为了弥补cookie的不足,cookie一方面是容量小，4k/8k，存几个电子邮件都不够，二来是全局的，容易被误用，盗用。 在HTML5中网络存储按照生命周期分为2种，一种是基于会话(session),这种存储周期只是当前会话，当网页[注1]被关被后，或者被转到其他网站后，存储也就被销毁； sessionStorage.varName = “生成新变量”; sessionStorage.varName = “变量操作”; delete sessionStorage.varName; //删除变量 另外一种是本地存储，当网页下次被打开的时候，你仍然可以访问上次打开该网页时存储的数据，比如本地存储的网站用户名就可以使用这种方式。 用法和基于会话的存储一样，只是前缀名改成了localStorage localStorage.varName = “生成新变量”; localStorage.varName = “变量操作”; delete localStorage.varName; //删除变量 从上面可以看出web storage其实也只是解决了轻量级的数据存储问题，如果是大量的数据查询，比如商品列表，还是得靠数据库,HTML5中有Web Database来支持这一操作，基本操作和SQL一致。 注1：现在的浏览器基本都支持多窗口了，一个窗口对应一个网页 注2：官方参考]]></description>
			<content:encoded><![CDATA[<p>WebStorage的出现是为了弥补cookie的不足,cookie一方面是容量小，4k/8k，存几个电子邮件都不够，二来是全局的，容易被误用，盗用。<br />
在HTML5中网络存储按照生命周期分为2种，一种是基于会话(session),这种存储周期只是当前会话，当网页[注1]被关被后，或者被转到其他网站后，存储也就被销毁；</p>
<pre name="code" class="js">
sessionStorage.varName = “生成新变量”;
sessionStorage.varName = “变量操作”;
delete sessionStorage.varName;  //删除变量
</pre>
<p>另外一种是本地存储，当网页下次被打开的时候，你仍然可以访问上次打开该网页时存储的数据，比如本地存储的网站用户名就可以使用这种方式。<br />
用法和基于会话的存储一样，只是前缀名改成了localStorage</p>
<pre name="code" class="js">
localStorage.varName = “生成新变量”;
localStorage.varName = “变量操作”;
delete localStorage.varName;  //删除变量
</pre>
<p>从上面可以看出web storage其实也只是解决了轻量级的数据存储问题，如果是大量的数据查询，比如商品列表，还是得靠数据库,HTML5中有Web Database来支持这一操作，基本操作和SQL一致。<br />
注1：现在的浏览器基本都支持多窗口了，一个窗口对应一个网页<br />
注2：<a href="http://dev.w3.org/html5/webstorage/">官方参考</a></p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2011/12/26/html5web-storage/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>黑马程序员——多线程原来是这么简单</title>
		<link>http://software.intel.com/zh-cn/blogs/2011/12/16/400009328/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2011/12/16/400009328/#comments</comments>
		<pubDate>Fri, 16 Dec 2011 03:59:27 +0000</pubDate>
		<dc:creator>william_feng</dc:creator>
				<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[并行计算]]></category>
		<category><![CDATA[移动技术]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2011/12/16/400009328/</guid>
		<description><![CDATA[一直以来对于多线程有种恐惧恐惧感，不理解它到底是什么回事，感觉挺抽象的，自从听了传智播客的邹老师对于多线程的讲解，我可以很自信地说我多线程方面入门了，特别是邹老师对于多线程有一套独有的方法，那就是画图，通过画图可以很直观地告诉你多线程是什么回事，比如UI线程和主线程，前台线程和后台线程，通过案例的讲解让你发现多线程的美妙。以下简单从如何创建多线程开始。首先来看用单线程的缺点： 通过对比单线程和多线程，创建了一个winform小程序来对比，界面如下： 进入代码区： 首先建立一个循环999999999次的方法： view plaincopy to clipboardprint? 01./// 02./// 循环计数的方法 03./// 04.void CountTime() 05.{ 06. DateTime beginTime = DateTime.Now; 07. for (int i = 0; i &#60;= 999999999; i++) 08. { 09. 10. } 11. TimeSpan ts = DateTime.Now.Subtract(beginTime); 12. MessageBox.Show("执行完毕！！"+ts.TotalMilliseconds); 13.} /// /// 循环计数的方法 /// void CountTime() { DateTime beginTime = DateTime.Now; for [...]]]></description>
			<content:encoded><![CDATA[<p>一直以来对于多线程有种恐惧恐惧感，不理解它到底是什么回事，感觉挺抽象的，自从听了传智播客的邹老师对于多线程的讲解，我可以很自信地说我多线程方面入门了，特别是邹老师对于多线程有一套独有的方法，那就是画图，通过画图可以很直观地告诉你多线程是什么回事，比如UI线程和主线程，前台线程和后台线程，通过案例的讲解让你发现多线程的美妙。以下简单从如何创建多线程开始。首先来看用单线程的缺点：</p>
<p>通过对比单线程和多线程，创建了一个winform小程序来对比，界面如下：</p>
<p><img src="http://hi.csdn.net/attachment/201111/7/0_1320632315B09J.gif" alt="null" /><br />
进入代码区：</p>
<p>首先建立一个循环999999999次的方法：</p>
<p>view plaincopy to clipboardprint?<br />
01.///<br />
02./// 循环计数的方法<br />
03.///</p>
<p>04.void CountTime()<br />
05.{<br />
06. DateTime beginTime = DateTime.Now;<br />
07. for (int i = 0; i &lt;= 999999999; i++)<br />
08. {<br />
09.<br />
10. }<br />
11. TimeSpan ts = DateTime.Now.Subtract(beginTime);<br />
12. MessageBox.Show("执行完毕！！"+ts.TotalMilliseconds);<br />
13.}<br />
///<br />
/// 循环计数的方法<br />
///</p>
<p>void CountTime()<br />
{<br />
DateTime beginTime = DateTime.Now;<br />
for (int i = 0; i &lt;= 999999999; i++)<br />
{</p>
<p>}<br />
TimeSpan ts = DateTime.Now.Subtract(beginTime);<br />
MessageBox.Show("执行完毕！！"+ts.TotalMilliseconds);<br />
}回到界面单击“单线程的缺点”这个按钮，编写事件代码如下：</p>
<p>view plaincopy to clipboardprint?<br />
01.//单线程的缺点<br />
02.private void btnSingleThread_Click(object sender, EventArgs e)<br />
03.{<br />
04. CountTime();<br />
05.}<br />
//单线程的缺点<br />
private void btnSingleThread_Click(object sender, EventArgs e)<br />
{<br />
CountTime();<br />
}<br />
点击运行，由于不能演示看，你会看到你无法拖动这个窗口移动摇晃，好像界面卡死了一样，过了一会儿，因为循环计数结束，弹出如下窗口：<br />
<img src="http://hi.csdn.net/attachment/201111/7/0_13206326633Eh2.gif" alt="null" /><br />
2）那么如何解决这种UI卡死的问题呢，因为之前单单用到单线程的而出现卡死的问题是因为界面运行的时候，其实主线程只能去处理计数，而根本没有时间去处理你偶外的“拖动摇晃”这个事件，之道计数这个事情做完之后才会过来做“拖动摇晃”的这个事件，为了解决这个“假死”的事情，就要用到多线程技术，点击界面的“多线程”按钮，如下代码：</p>
<p>view plaincopy to clipboardprint?<br />
01. //使用多线程来解决UI卡死问题<br />
02. private void btnMulTread_Click(object sender, EventArgs e)<br />
03. {<br />
04. //ThreadStart ts = new ThreadStart(CountTime);<br />
05. //Thread th = new Thread(ts);<br />
06. //创建线程对象 传入要线程执行的方法<br />
07. Thread th = new Thread(CountTime);<br />
08. //将线程设置为后台线程（当所有的前台线程结束后，后台线程会自动退出)<br />
09. th.IsBackground = true;<br />
10. //启动线程执行方法<br />
11. th.Start();<br />
12.<br />
13.<br />
14. }<br />
//使用多线程来解决UI卡死问题<br />
private void btnMulTread_Click(object sender, EventArgs e)<br />
{<br />
//ThreadStart ts = new ThreadStart(CountTime);<br />
//Thread th = new Thread(ts);<br />
//创建线程对象 传入要线程执行的方法<br />
Thread th = new Thread(CountTime);<br />
//将线程设置为后台线程（当所有的前台线程结束后，后台线程会自动退出)<br />
th.IsBackground = true;<br />
//启动线程执行方法<br />
th.Start();</p>
<p>}<br />
这样点击运行并点击“多线程”按钮来执行的话，你会发现运行过程中你可以拖动窗口，非常流畅地拖动着走，直到运行结束弹出如下消息窗口：<br />
<img src="http://hi.csdn.net/attachment/201111/7/0_1320633134408Y.gif" alt="null" /><br />
细心的你可能会发现上面两个执行时间不一样，单线程用的时间比多线程用的少那么一点点，原因是因为CPU要来回转过去执行UI线程和计数线程，其实多线程的实际上不是同时执行，只是因为CPU处理速度太快了，可以非常快速地来回在各个线程之间切换执行，就好像我们先烧开水，然后不用去等开水开了就可以去洗衣服一样，因为CPU处理的速度太快了，我们人裸眼根本察觉不到它在各个线程之间不停地切换，感觉好像是同时运行一样。自从终于可以对多线程有一个入门的认识了。</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2011/12/16/400009328/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>VTune(TM) Amplifier XE 在 Ubuntu* 11.04 上使用碰到的问题</title>
		<link>http://software.intel.com/zh-cn/blogs/2011/12/15/vtunetm-amplifier-xe-ubuntu-1104/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2011/12/15/vtunetm-amplifier-xe-ubuntu-1104/#comments</comments>
		<pubDate>Thu, 15 Dec 2011 06:59:39 +0000</pubDate>
		<dc:creator>Peter Wang (Intel)</dc:creator>
				<category><![CDATA[并行计算]]></category>
		<category><![CDATA[英特尔® 软件网络 2.0]]></category>
		<category><![CDATA["VTune Amplifier XE"]]></category>
		<category><![CDATA[Ubuntu 11.04]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2011/12/15/vtunetm-amplifier-xe-ubuntu-1104/</guid>
		<description><![CDATA[软件性能调试工具在Ubuntu* 11.04上碰到的问题，及解决办法]]></description>
			<content:encoded><![CDATA[<p><a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2011/12/Ubuntu11.04.jpg"></a><a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2011/12/Ubuntu11.041.jpg"></a>在Ubuntu* 11.04上通过Sudo安装完Intel(R) VTune(TM) Amplifier XE 2011。整个过程没有任何报错信息。</p>
<p>使用amplxe-gui，调用工具的图形界面，创建一个项目，选择目标的应用程序。然后通过工具对目标程序进行热点分析（Hotspots Analysis）, 意外得到出错信息。</p>
<p><a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2011/12/Ubuntu11.041.jpg"><img src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2011/12/Ubuntu11.041.jpg" alt="" width="766" height="272" /></a></p>
<p>同样的问题也会发生在并行性分析（Concurrency Analysis）和锁及等待分析(Locks And Waits Analysis)。</p>
<p>究其原因，Ubuntu* 10.10以后的版本对于一个普通用户在使用ptrace追踪进程时，仅允许被追踪进程的父进程ptrace 应用程序的进程。</p>
<p>而VTune Amplifier XE并非应用程序的父进程。怎么去除这个限制呢？根据出错信息的提示：</p>
<p>$sudo echo 0 &gt; /proc/sys/kernel/yama/ptrace_scope</p>
<p>bash: /proc/sys/kernel/yama/ptrace_scope: Permission denied</p>
<p>应该使用：</p>
<p>$echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope</p>
<p>[sudo] password for peter:</p>
<p>0</p>
<p>这样, VTune(TM) Amplifier XE 就可以正常工作了。</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2011/12/15/vtunetm-amplifier-xe-ubuntu-1104/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Silverlight 4 中四种多线程编程技术</title>
		<link>http://software.intel.com/zh-cn/blogs/2011/12/06/silverlight-4/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2011/12/06/silverlight-4/#comments</comments>
		<pubDate>Tue, 06 Dec 2011 09:45:43 +0000</pubDate>
		<dc:creator>lbuskeep</dc:creator>
				<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[并行计算]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2011/12/06/silverlight-4/</guid>
		<description><![CDATA[  在上篇文章中，我们介绍了Silverlight 4编程环境下的五种多线程编程技巧。在本篇中，我们将介绍另外四种Silverlight 4多线程编程中的支持技术。 　　1.使用WaitHandle 　　等待句柄应当是你进行多线程编程的必备装备。由于我们的主要兴趣点在于Silverlight多线程编程相关的内容，所以我们不想再深入探讨WaitHandle。但在此为你提供一个典型的例子，告诉你使用WaitHandle的基本方法。 　　清单1: public partial class MainPage : UserControl 　　AutoResetEvent handle = new AutoResetEvent(true); 　　public MainPage() 　　InitializeComponent(); 　　new Thread(() =&#62; 　　while (true) 　　handle.WaitOne(); 　　this.Dispatcher.BeginInvoke(() =&#62; 　　this.TextBlock1.Text = DateTime.Now.ToString(); 　　}); 　　}).Start(); 　　private void Button_Click(object sender, RoutedEventArgs e) 　　handle.Set(); 　2.使用定时器 　　System.Thread.Timer是一个多线程的计时器。这是一个简单的轻量级的计时器，使用回调方法，并由线程池中线程提供相应的服务。让我们看一个相关的例子： 　　清单2：(参考示例页面TimerTestPage.xaml) 　　 　　namespace SilverlightMultiThread 　　public partial class TimerTestPage : Page 　　System.Threading.SynchronizationContext _syncContext; [...]]]></description>
			<content:encoded><![CDATA[<p> </p>
<p>在上篇文章中，我们介绍了Silverlight 4编程环境下的五种多线程编程技巧。在本篇中，我们将介绍另外四种Silverlight 4多线程编程中的支持技术。</p>
<p>　　1.使用WaitHandle</p>
<p>　　等待句柄应当是你进行多线程编程的必备装备。由于我们的主要兴趣点在于Silverlight多线程编程相关的内容，所以我们不想再深入探讨WaitHandle。但在此为你提供一个典型的例子，告诉你使用WaitHandle的基本方法。</p>
<p>　　清单1:</p>
<p>public partial class MainPage : UserControl</p>
<p>　　AutoResetEvent handle = new AutoResetEvent(true);</p>
<p>　　public MainPage()</p>
<p>　　InitializeComponent();</p>
<p>　　new Thread(() =&gt;</p>
<p>　　while (true)</p>
<p>　　handle.WaitOne();</p>
<p>　　this.Dispatcher.BeginInvoke(() =&gt;</p>
<p>　　this.TextBlock1.Text = DateTime.Now.ToString();</p>
<p>　　});</p>
<p>　　}).Start();</p>
<p>　　private void Button_Click(object sender, RoutedEventArgs e)</p>
<p>　　handle.Set();</p>
<p>　2.使用定时器</p>
<p>　　System.Thread.Timer是一个多线程的计时器。这是一个简单的轻量级的计时器，使用回调方法，并由线程池中线程提供相应的服务。让我们看一个相关的例子：</p>
<p>　　清单2：(参考示例页面TimerTestPage.xaml)</p>
<p>　　</p>
<p>　　namespace SilverlightMultiThread</p>
<p>　　public partial class TimerTestPage : Page</p>
<p>　　System.Threading.SynchronizationContext _syncContext;</p>
<p>　　System.Threading.Timer _timer;</p>
<p>　　private int _flag = 0;</p>
<p>　　public TimerTestPage()</p>
<p>　　InitializeComponent();</p>
<p>　　//UI线程</p>
<p>　　_syncContext = System.Threading.SynchronizationContext.Current;</p>
<p>　　//输出当前时间</p>
<p>　　txtMsg.Text = DateTime.Now.ToString() + \r\n;</p>
<p>　　_timer = new System.Threading.Timer(MyTimerCallback, helltimer, 3000, 1000);</p>
<p>　　private void MyTimerCallback(object state)</p>
<p>　　string result = string.Format({0} - {1}: \r\n, DateTime.Now.ToString(), (string)state);</p>
<p>　　_syncContext.Post(delegate { txtMsg.Text += result; }, null);</p>
<p>　　_flag++;</p>
<p>　　if (_flag == 5)</p>
<p>　　_timer.Change(5000, 500);</p>
<p>　　else if (_flag == 10)</p>
<p>　　_timer.Dispose();</p>
<p>有以下几点值得注意。</p>
<p>　　第一，明确传递给定时器的参数：方法MyTimerCallback表示在线程池中执行的方法。第二个参数(在本例中的字符串)代表了传递给方法MyTimerCallback的内容。第三个参数详细说明方法MyTimerCallback被调用之前迟延时间的长短，以毫秒为单位。第四个参数是调用MyTimerCallback方法的时间间隔的说明，以毫秒为单位。</p>
<p>　　第二，我们已经使用了SynchronizationContext对象，因为线程上下文是清晰易知的。还要注意，在方法MyTimerCallback中我们调用了它的Post方法来修改UI线程中的内容。最后，通过定时器的Change方法，我们指定在该方法执行5次后，把开始时间设置为五分钟，计时器方法调用的时间间隔为5毫秒。</p>
<p>3.使用DispatcherTimer</p>
<p>　　DispatchTimer第一次亮相是在Silverlight(WPF)中作为一个后台线程计时器。与原System.Threading.Timer相比，不同之处在于DispatchTimer是真正的在后台线程中独立执行的，而定时器Timer仍然在UI线程中执行，每隔一个指定的时间接管UI线程的控制权。总体来看，DispatchTimer主要适合于调度任务的情况。在这种情况下，我们可以根据实际要求设置等待时间。请参考下面的示例。</p>
<p>　　清单3:</p>
<p>　　</p>
<p>　　public partial class MainPage : UserControl</p>
<p>　　DispatcherTimer timer;</p>
<p>　　public MainPage()</p>
<p>　　InitializeComponent();</p>
<p>　　timer = new DispatcherTimer();</p>
<p>　　timer.Tick += (s, e) =&gt; {</p>
<p>　　//每隔1000毫秒发生一次</p>
<p>　　//修改UI线程中的对象</p>
<p>　　this.TextBlock1.Text = DateTime.Now.ToString();</p>
<p>　　};</p>
<p>　　timer.Interval = TimeSpan.FromMilliseconds(1000);</p>
<p>　　timer.Start();</p>
<p>　　事实上，除StoryBoard组件之外dispatcherTimer也是Silverlight编程中实现动画效果的一种重要技术。当然，我们应该当心使用dispatcherTimer有可能导致创建太多的后台线程，从而有可能导致增加CPU的负荷而降低效率。<br />
4.使用BackgroundWorker</p>
<p>　　System.ComponentModel.BackgroundWorker首次出现在NET 2.0中，用于简化Windows窗体应用程序多线程交互相关的编码过程。现在，它也可用于Silverlight环境中。在后台实现中，BackgroundWorker使用了Dispatcher组件，并把所有多线程相关的复杂内容封装在一个黑盒子中，为您提供最易于使用和现成的解决方案。整体来说，BackgroundWorker非常适合从事单一的，异步的，并在后台运行的长时间的任务。</p>
<p>　　5.使用.NET Reflector进一步跟踪观察</p>
<p>　　现在，让我们使用.NET Reflector来进一步观察BackgroundWorker类的内容编码情形。</p>
<p>　　清单4:</p>
<p>　　</p>
<p>　　public class BackgroundWorker</p>
<p>　　// 事件声明</p>
<p>　　public event DoWorkEventHandler DoWork;</p>
<p>　　public event ProgressChangedEventHandler ProgressChanged;</p>
<p>　　public event RunWorkerCompletedEventHandler RunWorkerCompleted;</p>
<p>　　// 方法声明</p>
<p>　　public BackgroundWorker();</p>
<p>　　public void CancelAsync();</p>
<p>　　protected virtual void OnDoWork(DoWorkEventArgs e);</p>
<p>　　protected virtual void OnProgressChanged(ProgressChangedEventArgs e);</p>
<p>　　protected virtual void OnRunWorkerCompleted(RunWorkerCompletedEventArgs e);</p>
<p>　　public void ReportProgress(int percentProgress);</p>
<p>　　public void ReportProgress(int percentProgress, object userState);</p>
<p>　　public void RunWorkerAsync();</p>
<p>　　public void RunWorkerAsync(object argument);</p>
<p>　　// 属性定义</p>
<p>　　public bool CancellationPending { get; }</p>
<p>　　public bool IsBusy { get; }</p>
<p>　　public bool WorkerReportsProgress { get; set; }</p>
<p>　　public bool WorkerSupportsCancellation { get; set; }</p>
<p>　　从各自的名称来看，你会很容易想象，上面大多成员都是常用的。为了简便起见，我们将不再进行相关的深入分析。但是，我们将构建一个具体的例子，来看一个典型的使用BackgroundWorker的案例。</p>
<p>　　清单5:</p>
<p>　　</p>
<p>　　namespace SilverlightMultiThread</p>
<p>　　public partial class BackgroundWorkerTestPage : Page</p>
<p>　　System.ComponentModel.BackgroundWorker _backgroundWorker;</p>
<p>　　public BackgroundWorkerTestPage()</p>
<p>　　InitializeComponent();</p>
<p>　　_backgroundWorker = new System.ComponentModel.BackgroundWorker();</p>
<p>　　_backgroundWorker.WorkerSupportsCancellation = true;</p>
<p>　　_backgroundWorker.WorkerReportsProgress = true;</p>
<p>　　_backgroundWorker.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(_backgroundWorker_ProgressChanged);</p>
<p>　　_backgroundWorker.DoWork += new System.ComponentModel.DoWorkEventHandler(_backgroundWorker_DoWork);</p>
<p>　　_backgroundWorker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(_backgroundWorker_RunWorkerCompleted);</p>
<p>　　private void btnStart_Click(object sender, RoutedEventArgs e)</p>
<p>　　if (!_backgroundWorker.IsBusy)</p>
<p>　　_backgroundWorker.RunWorkerAsync(Need Parameter!);</p>
<p>　　private void btnCancel_Click(object sender, RoutedEventArgs e)</p>
<p>　　if (_backgroundWorker.WorkerSupportsCancellation)</p>
<p>　　_backgroundWorker.CancelAsync();</p>
<p>　　void _backgroundWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)</p>
<p>　　for (int i = 0; i 10; i++)</p>
<p>　　if ((_backgroundWorker.CancellationPending == true))</p>
<p>　　e.Cancel = true;</p>
<p>　　break;</p>
<p>　　else</p>
<p>　　System.Threading.Thread.Sleep(1000);</p>
<p>　　_backgroundWorker.ReportProgress((i + 1) * 10, i);</p>
<p>　　e.Result = Complete!;</p>
<p>　　void _backgroundWorker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)</p>
<p>　　txtProgress.Text = string.Format(Progress:{0}%; Parameter: {1},</p>
<p>　　e.ProgressPercentage,</p>
<p>　　e.UserState);</p>
<p>　　void _backgroundWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)</p>
<p>　　if (e.Error != null)</p>
<p>　　txtMsg.Text += e.Error.ToString() + \r\n;</p>
<p>　　else if (e.Cancelled)</p>
<p>　　txtMsg.Text += Cancelled!\r\n;</p>
<p>　　else</p>
<p>　　txtMsg.Text += e.Result.ToString() + \r\n;</p>
<p>　　整体而言，BackgroundWorker适合运行在一个单独的线程，特别是运行在一个非UI线程上且耗时的操作，以防止用户界面停止响应。上面，我们采用了一个“Cancel”按钮来取消线程的执行—通过判断线程是否可以取消(通过属性WorkerSupportsCancellation)。然后，我们调用方法CancelAsync暂停线程。相应地，该方法RunWorkerAsync用于启动线程，同时传递进可能的需要的参数。正如你所见，真正的异步工作是在方法_backgroundWorker_DoWork中进行的。同时，它使用ReportProgress方法报告当前进度，另外一个相关的方法_backgroundWorker_ProgressChanged用于负责在UI线程上呈现这个进度。一旦线程终止或暂停，另外一个相关方法_backgroundWorker_RunWorkerCompleted即被激活，并输出相关的提示信息。<br />
6.总结</p>
<p>　　在本系列的两篇文章中，我们总结了开发Silverlight多线程应用程序的典型的技术支持。然而，编写多线程Silverlight应用程序并不容易，如文首所暗示的，我们刚刚触及了这些内容的皮毛。因此，在你的实际工作中考虑使用多线程编程技术之前，高度建议你借鉴一下微软有关的建议。老实说，选择多线程技术在很大程度上意味着你必须面对并发锁定和同步机制等技术问题。但无论如何，是否在Sivlerlight项目中引入多线程技术取决于你的最后决断。</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2011/12/06/silverlight-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>虚拟化环境的部署与扩展</title>
		<link>http://software.intel.com/zh-cn/blogs/2011/12/06/400009344/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2011/12/06/400009344/#comments</comments>
		<pubDate>Tue, 06 Dec 2011 05:17:17 +0000</pubDate>
		<dc:creator>Bruce Chen 陈宇达 (Intel)</dc:creator>
				<category><![CDATA[并行计算]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2011/12/06/400009344/</guid>
		<description><![CDATA[这是一篇讲述虚拟化环境的部署与扩展的白皮书，供参考。谢谢 虚拟化环境的部署与扩展]]></description>
			<content:encoded><![CDATA[<p>这是一篇讲述虚拟化环境的部署与扩展的白皮书，供参考。谢谢<br />
<a href='http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2011/12/虚拟化环境的部署与扩展.pdf'>虚拟化环境的部署与扩展</a></p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2011/12/06/400009344/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>服务器虚拟化部署优势</title>
		<link>http://software.intel.com/zh-cn/blogs/2011/12/06/400009341/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2011/12/06/400009341/#comments</comments>
		<pubDate>Tue, 06 Dec 2011 05:15:02 +0000</pubDate>
		<dc:creator>Bruce Chen 陈宇达 (Intel)</dc:creator>
				<category><![CDATA[并行计算]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2011/12/06/400009341/</guid>
		<description><![CDATA[下面是一篇讲述服务器虚拟化部署优势的白皮书，供参考。谢谢 虚拟化平台部署优势]]></description>
			<content:encoded><![CDATA[<p>下面是一篇讲述服务器虚拟化部署优势的白皮书，供参考。谢谢<br />
<a href='http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2011/12/虚拟化平台部署优势.pdf'>虚拟化平台部署优势</a></p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2011/12/06/400009341/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>关键业务应用的虚拟化</title>
		<link>http://software.intel.com/zh-cn/blogs/2011/12/06/400009338/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2011/12/06/400009338/#comments</comments>
		<pubDate>Tue, 06 Dec 2011 05:10:33 +0000</pubDate>
		<dc:creator>Bruce Chen 陈宇达 (Intel)</dc:creator>
				<category><![CDATA[并行计算]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2011/12/06/400009338/</guid>
		<description><![CDATA[附件是针对关键业务应用进行虚拟化的一篇白皮书，供参考。 关键业务应用的虚拟化]]></description>
			<content:encoded><![CDATA[<p>附件是针对关键业务应用进行虚拟化的一篇白皮书，供参考。<br />
<a href='http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2011/12/关键业务应用进行虚拟化.pdf'>关键业务应用的虚拟化</a></p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2011/12/06/400009338/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

