<?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/%e8%bd%af%e4%bb%b6%e5%bc%80%e5%8f%91%e5%b7%a5%e5%85%b7/feed/" rel="self" type="application/rss+xml" />
	<link>http://software.intel.com/zh-cn/blogs</link>
	<description></description>
	<lastBuildDate>Mon, 28 May 2012 14:23:20 +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>Intel MKL函数,如何得到相同的计算结果？</title>
		<link>http://software.intel.com/zh-cn/blogs/2012/05/22/intel-mkl-2/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2012/05/22/intel-mkl-2/#comments</comments>
		<pubDate>Tue, 22 May 2012 07:20:42 +0000</pubDate>
		<dc:creator>Chao Y (Intel)</dc:creator>
				<category><![CDATA[并行计算]]></category>
		<category><![CDATA[软件开发工具]]></category>
		<category><![CDATA[MKL]]></category>
		<category><![CDATA[MKL 函数]]></category>
		<category><![CDATA[结果不同]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2012/05/22/intel-mkl-2/</guid>
		<description><![CDATA[在运行程序时，我们总希望多次运行的结果，是完全一致，甚至在不同的机器与不同的OS中，程序运行的结果每一位都完全相同。 事实上，程序往往很难保证做到这一点。 为什么呢？ 我们先看一个简单的例子： 当程序使用单精度或者双精度的浮点数时， 浮点数有一定的精度的限制。 单精度的浮点数，使用23位二进制表示的尾数。 双精度浮点数，使用52位的二进制（http://en.wikipedia.org/wiki/IEEE_754-1985）。  如果，程序中计算下面的表达式：         double d1,d2,d3,d4,d5;         d1 = 1e-63;         d2 = 1;         d3= -1;          d4 = (d1+ d2) +d3;         d5 = d1+ (d2 +d3);        printf("d4=%e\n",d4);        printf("d5=%e\n",d5);    通常，它的结果为：         d4=0.000000e+000         d5=1.000000e-063 尽管数学表达上， d4 应该有和d5 完全相同的计算结果。但是，由于浮点数的有限精度，（d1+d2），在计算机的值为1. 最终，d4,d5的结果并不完全相同。 如果程序调用Intel MKL 函数，下面的一些因素，往往会对我们的计算结果产生影响： [...]]]></description>
			<content:encoded><![CDATA[<p>在运行程序时，我们总希望多次运行的结果，是完全一致，甚至在不同的机器与不同的OS中，程序运行的结果每一位都完全相同。</p>
<p>事实上，程序往往很难保证做到这一点。 为什么呢？ 我们先看一个简单的例子： 当程序使用单精度或者双精度的浮点数时， 浮点数有一定的精度的限制。 单精度的浮点数，使用23位二进制表示的尾数。 双精度浮点数，使用52位的二进制（<a href="http://en.wikipedia.org/wiki/IEEE_754-1985">http://en.wikipedia.org/wiki/IEEE_754-1985</a>）。</p>
<p> 如果，程序中计算下面的表达式：</p>
<p>        double d1,d2,d3,d4,d5;<br />
        d1 = 1e-63;<br />
        d2 = 1;<br />
        d3= -1;</p>
<p>         d4 = (d1+ d2) +d3;<br />
        d5 = d1+ (d2 +d3);</p>
<p>       printf("d4=%e\n",d4);<br />
       printf("d5=%e\n",d5);</p>
<p>   通常，它的结果为：<br />
        d4=0.000000e+000<br />
        d5=1.000000e-063</p>
<p>尽管数学表达上， d4 应该有和d5 完全相同的计算结果。但是，由于浮点数的有限精度，（d1+d2），在计算机的值为1. 最终，d4,d5的结果并不完全相同。</p>
<p>如果程序调用Intel MKL 函数，下面的一些因素，往往会对我们的计算结果产生影响：</p>
<p> 1&gt; <strong>内存对齐：</strong>我们的处理器往往提供了一些专门的指令，对16 byte 或 32 byte (AVX ) 对齐内存地址进行存取操作。 当程序运行时，对齐或不对齐输入数据的地址，运行的代码可能有略微差别。最终，程序的计算结果，可能不是完全一致。</p>
<p>2&gt;<strong> 多线程的设置</strong>： Intel MKL 函数已经是多核优化后的函数，程序运行多线的数目不同，带来相应的数值精度上也会细微的误差。</p>
<p> 3&gt;<strong> 针对不同处理器的优化代码</strong>： Intel MKL 能够充分利用处理器的指令集，来取得程序的最高性能。 这样在不同的处理器上， 程序运行的代码可能并不是完全一致，从而最终的的结果，可能也略有差别。</p>
<p>新的MKL 11.0提供了conditional bitwise reproducible (CBWR)的特性。 在满足一定的条件下，它能保证MKL函数有相同的结果。如果 1）输入/输出的数据地址按照16或 32字节对齐 （ 选择执行SSE指令需要16 byte 对齐，AVX1指令32 byte 对齐）2）运行的线程数目相同 3）在同一可执行文件中被调用， 那么Intel MKL函数可以在多次执行中，有相同的计算结果。</p>
<p> 程序不同处理器上运行的时候，可能运行不同的优化代码。比如， 在较旧Intel® Pentium® 4 处理器上， MKL可能运行SSE2 优化代码，而在支持的AXV指令的新的机器上，MKL 的函数可能运行AVX指令的优化代码。 这样，Intel MKL函数能够根据不同处理器的特性，提供高效的优化代码。但是，当这些代码，有不完全相同的数据处理顺序时，不完全一致的代码可能产生的最有的数值结果可能也不完全一致。 在MKL 11.0 中， 提供的一些新的函数，与环境变量。能够帮助用户来来控制取得一致的计算结果。</p>
<p>下面我们看一下例子：</p>
<p>  1&gt; 为确保在Intel 以及Intel 兼容的支持SSE2 指令的处理上，有一致的计算结果， 我们可以将程序须设置固定的线程数目， 保证输入输出数据的地址对齐， 并调用以下的MKL 函数：</p>
<p>         mkl_cbwr_set(MKL_CBWR_COMPATIBLE) 或设置环境变量：MKL_CBWR_BRANCH = "COMPATIBLE"</p>
<p> 2&gt;在支持SSE4.1 Intel 的处理器上， 为确保MKL 函数有相同的结果。我们可以将程序须设置固定的线程数目，保证输入输出数据的地址对齐， 并调用以下的MKL 函数： </p>
<p>           mkl_cbwr_set(MKL_CBWR_SSE4_1) 或设置环境变量： MKL_CBWR_BRANCH = "SSE4_1"</p>
<p>需要说明的是， 如果我们选择了特定CPU优化的代码， 很自然，针对一些新的处理器，MKL 可能会有一些性能开销。 比如，对于矩阵与矩阵乘法的函数（xGEMM）, AVX 优化代码的性能有近乎SSE2优化代码的两倍性能。在支持AVX机器上，我们指定，该函数运行SSE2的代码，会有不少的性能损失。对于其他的一些例子，选择特定的优化代码，可能有10%-20%的性能开销。</p>
<p>相关培训材料： <a href="http://software.intel.com/en-us/articles/conditional-bitwise-reproducibility/">http://software.intel.com/en-us/articles/conditional-bitwise-reproducibility/</a></p>
<p>下载与测试<a href="https://softwareproductsurvey.intel.com/survey/149957/2363/?LQID=7&amp;MKL=MKL">Intel MKL 11.0 Beta</a>：</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2012/05/22/intel-mkl-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenMP 概述</title>
		<link>http://software.intel.com/zh-cn/blogs/2012/05/07/openmp-4/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2012/05/07/openmp-4/#comments</comments>
		<pubDate>Mon, 07 May 2012 10:19:20 +0000</pubDate>
		<dc:creator>xwebsite</dc:creator>
				<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[并行计算]]></category>
		<category><![CDATA[软件开发工具]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2012/05/07/openmp-4/</guid>
		<description><![CDATA[根据计算平台和规模的不同，并行计算可以分为两种：第一种是基于单一计算机系统的多核处理器或多处理器进行多线程并行计算，采用共享存储的方式，主要的标准有OpenMP，如下左图所示；第二种就是基于多台计算机组件的集群（Cluster）计算系统进行并行计算，采用消息传递方式，主要的标准有MPI，如下右图所示。本文将主要介绍多线程方式的并行计算。 首先来了解一下单核处理器上程序运行方式，系统中包括操作系统和应用程序等都以进程（Process）形式存在，当程序结束时这个进程也就跟着消亡。每个进程中至少包含一个线程（Thread），一个线程用于完成程序的某个功能，一个程序中一般都包含多个线程，所有的这些线程在系统中都成队列形式。对于一个核心的处理器来说，某一时刻，它只能处理一个线程。这个线程处理之后就处理下一个线程，依次循环处理。由于CPU的主频都非常高，如Intel的奔四可到3GHz，所以每个线程处理的时间都非常短，以致我们并不会察觉。但是它们实际上是以串行的形式在CPU上运行。所以在物理上，对于单核处理器来说，是无法实现物理上的并行。在单核处理器上，即使使用多线程来分发程序，但实际上还是以单线程的形式在运行。 如果将执行核增加一个，那么在同一时刻，将会有两个线程在运行，这样将会在一定程度上提供计算机的运行速度，但对于某些单线程的程序过程来说，实际情况并没用得到改善。至于系统中的线程怎么分发到两个核上，这就是操作系统的任务了。很多应用程序都不止包含一个线程，一般都包含有多个线程，如用Spy++工具查看系统所有的线程，如下图所示： 这多个线程如果在一个执行核上运行，它们呈一个队列来执行。如果在两个执行核上运行的话，它们将呈两队来执行。如果某个程序中包括有四个线程，而这四个线程又分别在两个核上执行，那么执行该程序将节约一半的时间。但如果该程序是单线程，无论是单核还是多核，运行该程序所需的时间都将是一样的。所以，以前有人在某单线程程序中将一些程序分开放在两个线程中分别执行，效率得到了提高，节约将近一倍的时间，其原因就在此。 OpenMP提供的就是一个多线程编程标准，现在.Net平台也提供了并行编程的System.Threading.Tasks.Parallel类，可以使多个线程能够同时执行。如果直接采用多个线程去实现并行，需要经常处理线程或线程池，采用这些多线程编程标准可以简化并行开发，也不必直接处理线程或线程池。 在C/C++中采用OpenMP指令的格式如下： #pragma omp … 关键字omp表示这个指令是OpenMP指令，所以它会被OpenMP编译器处理，其他非OpenMP编译器将不会理会。由于OpenMP指令都预先定义了，所以很容易被识别出来。这样程序员编写的并行代码就可以在不同的平台上运行。如果平台不支持并行，也会直接跳过并行指令把程序当作串行程序来运行。 OpenMP提供了两种控制并行的结构：第一种就是提供了一个用于创建多线程程序的指令，这些线程相互之间是并行的，这个指令实际上就是创建了一些线程去执行并形体中的程序；第二种就是对已存在的并行结构进行分工的指令，像循环中的do指令（Fortran）或for（C/C ++）。 一个OpenMp程序通常都是从一个单线程程序开始，我们通常把这个单线程程序叫做主线程（Master Thread），在主线程的程序中应该要包含整个程序中需要使用的数据变量，包括全局变量。当主线程遇到并行结构时，将会创建新的线程来执行并形体中的程序。每个线程都会独立的执行并形体中的程序，相互之间不会影响，但是它们之间可以共用主线程里面定义的全局变量。在并行过程中具体哪些变量是共享的、哪些变量是线程私有的，可以通过条件clauses(…)对每个变量进行指定，这些条件用于并行线程中决定哪些可用。一个变量可以有三种类型，即shared、private和reduction。其中shared表示在并行结构中将有一个单独的内存位置来存放这个变量，所有的并行线程都可以使用这个变量，所有的并行线程将共享这块内存地址，因此，线程间的通信通过普通的读写操作方式就可以实现，当然，这个变量也可以随意被任何一个线程修改。相反，private变量将会有多个内存地址，每个线程里面一个。这个变量的所有读写操作都只限于本线程，其他线程是无法访问本线程中该变量的内存地址的。所以，一般都用于定义临时变量。reduction就有点难理解了，它具有shared和private的特征，就像它的字面意思一样，reduction属性用于需要下降的变量（指值的减少）。Reduction操作在很多程序中都非常重要，最常见的例子就是计算并行结构中最后的临时局部变量的总和。除了这三种之外，OpenMP还提供了许多其他数据属性参数。 多个OpenMP线程之间可以采用共享变量（shared）通过简单的读写操作来进行通信，但是这需要在多个线程中协调一致。如果协调不一致，可能会出现多个线程同时修改这个变量，或者这个线程正在读而那个线程又正在写，这些潜在的冲突都将导致数据的错误，因此，在多线程中必须避免这种情况，必须明确地协调好。在并行程序中设置同步（synchronization）就可以协调这些执行的多线程。最常见的两种情况就是相互排斥和事件同步，互斥就是在这段代码中通过一个线程不让其他线程读取这个共享变量。当很多线程正在修改同一个变量时，为了确保这个变量值是对的，在修改之前就需要进行互斥存取。OpenMP中提供了一个critical指标来表示互斥。事件同步常用于表示多线程间的事件，最简单的形式就是barrier阻塞。在并行程序中barrier指标表示在某点处每个线程都在这等待其他的线程也运行到这里，一旦所有的线程都达到这个点后，它们又继续执行。就像跑步的时候，有的人跑得快，有的人跑得慢，在跑了两圈的时候，所有人都在这里等待最后一个人，当最后一个人也跑到两圈的时候，然后大家又接着继续跑，这个过程就称为barrier阻塞。barrier指令能保证所有线程都执行了在barrier之前的代码。 一个典型的并行程序结构如下图所示： OpenMP API是一套非常简便的共享存储并行计算应用程序接口，它是一个多线程、共享存储的模型。线程间通过共享的变量进行交换，并可以通过线程同步来防止数据冲突，当然，同步是需要耗费很多的资源的，所以尽量减少同步的需要。]]></description>
			<content:encoded><![CDATA[<p>根据计算平台和规模的不同，并行计算可以分为两种：第一种是基于单一计算机系统的多核处理器或多处理器进行多线程并行计算，采用共享存储的方式，主要的标准有OpenMP，如下左图所示；第二种就是基于多台计算机组件的集群（Cluster）计算系统进行并行计算，采用消息传递方式，主要的标准有MPI，如下右图所示。本文将主要介绍多线程方式的并行计算。<br />
<img src="http://images.csdn.net/20120507/1.jpg" alt="null" /><br />
首先来了解一下单核处理器上程序运行方式，系统中包括操作系统和应用程序等都以进程（Process）形式存在，当程序结束时这个进程也就跟着消亡。每个进程中至少包含一个线程（Thread），一个线程用于完成程序的某个功能，一个程序中一般都包含多个线程，所有的这些线程在系统中都成队列形式。对于一个核心的处理器来说，某一时刻，它只能处理一个线程。这个线程处理之后就处理下一个线程，依次循环处理。由于CPU的主频都非常高，如Intel的奔四可到3GHz，所以每个线程处理的时间都非常短，以致我们并不会察觉。但是它们实际上是以串行的形式在CPU上运行。所以在物理上，对于单核处理器来说，是无法实现物理上的并行。在单核处理器上，即使使用多线程来分发程序，但实际上还是以单线程的形式在运行。<br />
如果将执行核增加一个，那么在同一时刻，将会有两个线程在运行，这样将会在一定程度上提供计算机的运行速度，但对于某些单线程的程序过程来说，实际情况并没用得到改善。至于系统中的线程怎么分发到两个核上，这就是操作系统的任务了。很多应用程序都不止包含一个线程，一般都包含有多个线程，如用Spy++工具查看系统所有的线程，如下图所示：<br />
<img src="http://images.csdn.net/20120507/2.jpg" alt="null" /><br />
这多个线程如果在一个执行核上运行，它们呈一个队列来执行。如果在两个执行核上运行的话，它们将呈两队来执行。如果某个程序中包括有四个线程，而这四个线程又分别在两个核上执行，那么执行该程序将节约一半的时间。但如果该程序是单线程，无论是单核还是多核，运行该程序所需的时间都将是一样的。所以，以前有人在某单线程程序中将一些程序分开放在两个线程中分别执行，效率得到了提高，节约将近一倍的时间，其原因就在此。<br />
<img src="http://images.csdn.net/20120507/3.jpg" alt="null" /><br />
OpenMP提供的就是一个多线程编程标准，现在.Net平台也提供了并行编程的System.Threading.Tasks.Parallel类，可以使多个线程能够同时执行。如果直接采用多个线程去实现并行，需要经常处理线程或线程池，采用这些多线程编程标准可以简化并行开发，也不必直接处理线程或线程池。</p>
<p>在C/C++中采用OpenMP指令的格式如下：</p>
<p>#pragma omp …</p>
<p>关键字omp表示这个指令是OpenMP指令，所以它会被OpenMP编译器处理，其他非OpenMP编译器将不会理会。由于OpenMP指令都预先定义了，所以很容易被识别出来。这样程序员编写的并行代码就可以在不同的平台上运行。如果平台不支持并行，也会直接跳过并行指令把程序当作串行程序来运行。</p>
<p>OpenMP提供了两种控制并行的结构：第一种就是提供了一个用于创建多线程程序的指令，这些线程相互之间是并行的，这个指令实际上就是创建了一些线程去执行并形体中的程序；第二种就是对已存在的并行结构进行分工的指令，像循环中的do指令（Fortran）或for（C/C ++）。</p>
<p>一个OpenMp程序通常都是从一个单线程程序开始，我们通常把这个单线程程序叫做主线程（Master Thread），在主线程的程序中应该要包含整个程序中需要使用的数据变量，包括全局变量。当主线程遇到并行结构时，将会创建新的线程来执行并形体中的程序。每个线程都会独立的执行并形体中的程序，相互之间不会影响，但是它们之间可以共用主线程里面定义的全局变量。在并行过程中具体哪些变量是共享的、哪些变量是线程私有的，可以通过条件clauses(…)对每个变量进行指定，这些条件用于并行线程中决定哪些可用。一个变量可以有三种类型，即shared、private和reduction。其中shared表示在并行结构中将有一个单独的内存位置来存放这个变量，所有的并行线程都可以使用这个变量，所有的并行线程将共享这块内存地址，因此，线程间的通信通过普通的读写操作方式就可以实现，当然，这个变量也可以随意被任何一个线程修改。相反，private变量将会有多个内存地址，每个线程里面一个。这个变量的所有读写操作都只限于本线程，其他线程是无法访问本线程中该变量的内存地址的。所以，一般都用于定义临时变量。reduction就有点难理解了，它具有shared和private的特征，就像它的字面意思一样，reduction属性用于需要下降的变量（指值的减少）。Reduction操作在很多程序中都非常重要，最常见的例子就是计算并行结构中最后的临时局部变量的总和。除了这三种之外，OpenMP还提供了许多其他数据属性参数。</p>
<p>多个OpenMP线程之间可以采用共享变量（shared）通过简单的读写操作来进行通信，但是这需要在多个线程中协调一致。如果协调不一致，可能会出现多个线程同时修改这个变量，或者这个线程正在读而那个线程又正在写，这些潜在的冲突都将导致数据的错误，因此，在多线程中必须避免这种情况，必须明确地协调好。在并行程序中设置同步（synchronization）就可以协调这些执行的多线程。最常见的两种情况就是相互排斥和事件同步，互斥就是在这段代码中通过一个线程不让其他线程读取这个共享变量。当很多线程正在修改同一个变量时，为了确保这个变量值是对的，在修改之前就需要进行互斥存取。OpenMP中提供了一个critical指标来表示互斥。事件同步常用于表示多线程间的事件，最简单的形式就是barrier阻塞。在并行程序中barrier指标表示在某点处每个线程都在这等待其他的线程也运行到这里，一旦所有的线程都达到这个点后，它们又继续执行。就像跑步的时候，有的人跑得快，有的人跑得慢，在跑了两圈的时候，所有人都在这里等待最后一个人，当最后一个人也跑到两圈的时候，然后大家又接着继续跑，这个过程就称为barrier阻塞。barrier指令能保证所有线程都执行了在barrier之前的代码。</p>
<p>一个典型的并行程序结构如下图所示：<br />
<img src="http://images.csdn.net/20120507/4.jpg" alt="null" /><br />
OpenMP API是一套非常简便的共享存储并行计算应用程序接口，它是一个多线程、共享存储的模型。线程间通过共享的变量进行交换，并可以通过线程同步来防止数据冲突，当然，同步是需要耗费很多的资源的，所以尽量减少同步的需要。</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2012/05/07/openmp-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C++编译器到底能帮我们把代码优化到什么程度？</title>
		<link>http://software.intel.com/zh-cn/blogs/2012/03/22/c-14/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2012/03/22/c-14/#comments</comments>
		<pubDate>Thu, 22 Mar 2012 04:28:02 +0000</pubDate>
		<dc:creator>hengyunabc123</dc:creator>
				<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[开放源代码]]></category>
		<category><![CDATA[软件开发工具]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2012/03/22/c-14/</guid>
		<description><![CDATA[一个简单的累加求和程序： 01.TYPE S=0; 02.for(int i = 0;i &#60; SIZE; i++) { 03. S += a[i]; 04.} 很多人都觉得这个程序写得不好，编译器不能生成很好的汇编代码。于是有了以下的几种“优化”： 01.#include 02.using namespace std; 03. 04.void main(int argc,char **argv) 05.{ 06.#define TYPE int 07.#define SIZE 10000 08. 09. TYPE* a=new TYPE[SIZE]; 10. for(int i = 0; i&#60;SIZE; ++i){ 11. a[i] = i; 12. } 13. //求和，通常版本 14. TYPE [...]]]></description>
			<content:encoded><![CDATA[<p>一个简单的累加求和程序：</p>
<p>01.TYPE S=0;<br />
02.for(int i = 0;i &lt; SIZE; i++) {<br />
03. S += a[i];<br />
04.}</p>
<p>很多人都觉得这个程序写得不好，编译器不能生成很好的汇编代码。于是有了以下的几种“优化”：</p>
<p>01.#include<br />
02.using namespace std;<br />
03.<br />
04.void main(int argc,char **argv)<br />
05.{<br />
06.#define TYPE int<br />
07.#define SIZE 10000<br />
08.<br />
09. TYPE* a=new TYPE[SIZE];<br />
10. for(int i = 0; i&lt;SIZE; ++i){<br />
11. a[i] = i;<br />
12. }<br />
13. //求和，通常版本<br />
14. TYPE S=0;<br />
15. for(int i = 0;i &lt; SIZE; i++) {<br />
16. S += a[i];<br />
17. }<br />
18. cout&lt;&lt;S&lt;&lt;endl;<br />
19.<br />
20. TYPE S2 = 0;<br />
21. //版本1：认为中间产生的变量i是多余的，改为用移动指针<br />
22. TYPE* end = a + SIZE;<br />
23. for( ; a != end; ) {<br />
24. S2 += *(a++);<br />
25. }<br />
26. cout&lt;&lt;S2&lt;&lt;endl;<br />
27.<br />
28. //版本1中把a移到了数组的最后，现在移回原来的位置<br />
29. a = end - SIZE;<br />
30.<br />
31. //版本2：认为循环次数太多了，可以改为减少循环次数<br />
32. TYPE S3 = 0;<br />
33. for(int i = 0; i &lt; SIZE; ){ //仅当SIZE为偶数时<br />
34. S3 += a[i++];<br />
35. S3 += a[i++];<br />
36. }<br />
37. cout&lt;&lt;S3&lt;&lt;endl;<br />
38.<br />
39. //版本3：认为版本2中会使CPU不能乱序执行，降低了效率，应该改为汇编，把中间结果放到独立的寄存器中<br />
40. //谢谢 menzi11 的文章，让我认识到程序中相关的数据会让CPU不能乱序执行。<br />
41. //这里用伪汇编代替<br />
42. TYPE S4 = 0;<br />
43.<br />
44. register TYPE r1 = 0;<br />
45. register TYPE r2 = 0;<br />
46. for(int i = 0; i &lt; SIZE; ){ //仅当SIZE为偶数时<br />
47. r1 += a[i++];<br />
48. r2 += a[i++];<br />
49. }<br />
50.<br />
51. cout&lt;&lt;r1 + r2&lt;&lt;endl;<br />
52.}</p>
<p>上面的几种版本都合理，但是这些优化都是建立在编译器不能生成高效的汇编代码的假设上的。</p>
<p>下面来看下编译器生成的结果（vs2010，release)：</p>
<p>01. for(int i = 0;i &lt; SIZE; i++) {<br />
02. S += a[i];<br />
03.013B1040 mov ebx,dword ptr [eax+4] //把a[0],a[4],a[8]...累加到ebx中<br />
04.013B1043 add ecx,dword ptr [eax-8] //把a[1],a[5],a[9]...累加到ecx中<br />
05.013B1046 add edx,dword ptr [eax-4] //把a[2],a[6],a[10]...累加到edx中<br />
06.013B1049 add esi,dword ptr [eax] //把a[3],a[7],a[11]...累加到esi中<br />
07.013B104B add dword ptr [ebp-4],ebx<br />
08.013B104E add eax,10h<br />
09.013B1051 dec dword ptr [ebp-8]<br />
10.013B1054 jne main+40h (13B1040h)<br />
11. }<br />
12. cout&lt;&lt;S&lt;&lt;endl;<br />
13.013B1056 mov eax,dword ptr [ebp-4]<br />
14.013B1059 add eax,esi<br />
15.013B105B add eax,edx<br />
16.013B105D mov edx,dword ptr [__imp_std::endl (13B204Ch)]<br />
17.013B1063 add ecx,eax //上面的3条add指令把ebx，ecx，edx，edi都加到ecx中，即ecx是累加结果</p>
<p>可见编译器生成的代码是最好的代码，消灭了中间变量i，减少了循环次数，消灭了会造成CPU不能乱序执行的因素。</p>
<p>BTW：</p>
<p>有人可能会有疑问：要是size不是偶数，编译器能生成类似的高效汇编代码不？</p>
<p>当SIZE = 9999时：</p>
<p>01.//当SIZE = 9999时，编译器把中间结果放到三个寄存器中，perfect<br />
02. for(int i = 0;i &lt; SIZE; i++) {<br />
03. S += a[i];<br />
04.01341030 add ecx,dword ptr [eax-8]<br />
05.01341033 add edx,dword ptr [eax-4]<br />
06.01341036 add esi,dword ptr [eax]<br />
07.01341038 add eax,0Ch<br />
08.0134103B dec ebx<br />
09.0134103C jne main+30h (1341030h)<br />
10. }</p>
<p>当SIZE = 9997 时：</p>
<p>01.//当SIZE = 9997时，有点复杂，先把a[0]到a[9995]累加到ecx和edx中<br />
02.//再把a[9996]入到edi中，最后把ecx，edi都加到edx中<br />
03.//edx压栈，调用operator&lt;&lt; 函数<br />
04. for(int i = 0;i &lt; SIZE; i++) {<br />
05.00D31024 xor eax,eax<br />
06. S += a[i];<br />
07.00D31026 add ecx,dword ptr [esi+eax*4]<br />
08.00D31029 add edx,dword ptr [esi+eax*4+4]<br />
09.00D3102D add eax,2<br />
10.00D31030 cmp eax,270Ch<br />
11.00D31035 jl main+26h (0D31026h)<br />
12. for(int i = 0;i &lt; SIZE; i++) {<br />
13.00D31037 cmp eax,270Dh<br />
14.00D3103C jge main+41h (0D31041h)<br />
15. S += a[i];<br />
16.00D3103E mov edi,dword ptr [esi+eax*4]<br />
17. }<br />
18. cout&lt;&lt;S&lt;&lt;endl;<br />
19.00D31041 mov eax,dword ptr [__imp_std::endl (0D3204Ch)]<br />
20.00D31046 add edx,ecx<br />
21.00D31048 mov ecx,dword ptr [__imp_std::cout (0D32050h)]<br />
22.00D3104E push eax<br />
23.00D3104F add edx,edi<br />
24.00D31051 push edx<br />
25.00D31052 call dword ptr [__imp_std::basic_ostream&lt;char,std::char_traits &gt;::operator&lt;&lt; (0D32048h)]</p>
<p>上面的分析都是SIZE，即数组的大小是已知情况下，那个数组大小是未知情况下，编译器又会怎样？</p>
<p>01.TYPE mySum(TYPE* a, int size){<br />
02. TYPE s = 0;<br />
03. for(int i = 0; i &lt; size; ++i){<br />
04. s += a[i];<br />
05. }<br />
06. return s;<br />
07.}</p>
<p>生成的汇编代码：</p>
<p>01.//先累加a[0] 到 a[size-2]<br />
02. TYPE s = 0;<br />
03.00ED100C xor esi,esi<br />
04. for(int i = 0; i &lt; size; ++i){<br />
05.00ED100E xor eax,eax<br />
06.00ED1010 cmp ebx,2<br />
07.00ED1013 jl mySum+27h (0ED1027h)<br />
08.00ED1015 dec ebx<br />
09. s += a[i];<br />
10.00ED1016 add ecx,dword ptr [edi+eax*4] //a[0],a[2],a[4]...加到ecx中<br />
11.00ED1019 add edx,dword ptr [edi+eax*4+4] //a[1],a[3],a[5]...加到edx中<br />
12.00ED101D add eax,2<br />
13.00ED1020 cmp eax,ebx<br />
14.00ED1022 jl mySum+16h (0ED1016h)<br />
15.00ED1024 mov ebx,dword ptr [size]<br />
16. for(int i = 0; i &lt; size; ++i){<br />
17.00ED1027 cmp eax,ebx //判断最后一个元素有没有加上<br />
18.00ED1029 jge mySum+2Eh (0ED102Eh)<br />
19. s += a[i];<br />
20.00ED102B mov esi,dword ptr [edi+eax*4] //当size是奇数是会执行，偶数时不会执行<br />
21.00ED102E add edx,ecx<br />
22. }</p>
<p>总结：C++的编译器生成的汇编代码在绝大多数情况下都和人写出的最好的汇编代码相当。</p>
<p>关键的一点是编译器会不断升级，适应新的cpu指令，体系等，手写的汇编代码则通常悲剧了。</p>
<p>知道编译器能优化到什么程度，编译器到底怎样优化，是程序员很重要的素质。</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2012/03/22/c-14/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Intel MKL 多线程设置</title>
		<link>http://software.intel.com/zh-cn/blogs/2012/03/20/intel-mkl/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2012/03/20/intel-mkl/#comments</comments>
		<pubDate>Tue, 20 Mar 2012 06:58:58 +0000</pubDate>
		<dc:creator>Chao Y (Intel)</dc:creator>
				<category><![CDATA[并行计算]]></category>
		<category><![CDATA[软件开发工具]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2012/03/20/intel-mkl/</guid>
		<description><![CDATA[对于多核程序，多线程对于程序的性能至关重要。 下面，我们将对Intel MKL 有关多线程方面的设置做一些介绍： 我们提到MKL 支持多线程，它包括的两个概念： 1&#62;MKL 是线程安全的： MKL在设计时，就保证它是一个线程安全的库函数。 也就是说，无论是在单个线程中调用MKL函数，还是在多个线程中同时使用Intel MKL 函数，都能够确保函数有正确的计算结果。 2&#62;MKL函数内部实现了多线程优化。许多MKL的函数，已经包括内部多线程的实现。用户调这些函数时，只需设置多线程的数目，MKL 函数的内部，就可以同时进行多个线程的并行计算。 Intel MKL 还提供了一个单线程版本的库函数，这个版本中，每个函数只运行串行代码。 我们需要在链接的时候，需要选择链接串行（单线程）的MKL函数，还是并行（多线程）的MKL 的函数。 下面我们提到的多线控制的方法，主要是针对的并行的MKL函数库。 那么，在MKL 的多线程库中， 如何设置MKL 多线程的数目呢？ Intel MKL 使用了OpenMP实现了多线程，所以OpenMP的环境变量与API对MKL 的多线程设置仍然有效。 除了OpenMP的方法外，MKL还提供了，其它的设置多线程的环境变量与API: 环境变量 对应的API 说明 对于的OMP的变量 MKL_NUM_THREADS mkl_set_num_threads 建议MKL 函数使用的多线程的数目。. OMP_NUM_THREADS OMP_NUM_THREADS omp_set_num_threads OpenMP提供的多线程设置的环境变量与API.   MKL_DYNAMIC mkl_set_dynamic 建议MKL根据计算问题，自动设置多线程的数目，线程数目不超过用户设定的线程的上限 OMP_DYNAMIC   需要说明的是，Intel MKL 提供的多线程设置的方法，优先级要高于OpenMP的方法。 比程序中，同时设置了下面的环境变量： &#62;export MKL_NUM_THREADS =1 &#62;export [...]]]></description>
			<content:encoded><![CDATA[<p>对于多核程序，多线程对于程序的性能至关重要。 下面，我们将对Intel MKL 有关多线程方面的设置做一些介绍：</p>
<p>我们提到MKL 支持多线程，它包括的两个概念：<br />
1&gt;MKL 是线程安全的： MKL在设计时，就保证它是一个线程安全的库函数。 也就是说，无论是在单个线程中调用MKL函数，还是在多个线程中同时使用Intel MKL 函数，都能够确保函数有正确的计算结果。</p>
<p>2&gt;MKL函数内部实现了多线程优化。许多MKL的函数，已经包括内部多线程的实现。用户调这些函数时，只需设置多线程的数目，MKL 函数的内部，就可以同时进行多个线程的并行计算。 Intel MKL 还提供了一个单线程版本的库函数，这个版本中，每个函数只运行串行代码。 我们需要在链接的时候，需要选择链接串行（单线程）的MKL函数，还是并行（多线程）的MKL 的函数。 下面我们提到的多线控制的方法，主要是针对的并行的MKL函数库。</p>
<p>那么，在MKL 的多线程库中， 如何设置MKL 多线程的数目呢？ Intel MKL 使用了OpenMP实现了多线程，所以OpenMP的环境变量与API对MKL 的多线程设置仍然有效。 除了OpenMP的方法外，MKL还提供了，其它的设置多线程的环境变量与API:</p>
<table border="1" cellspacing="0" cellpadding="0" align="left">
<tbody>
<tr>
<td valign="top"><strong>环境变量</strong></td>
<td valign="top"><strong>对应的API</strong></td>
<td valign="top"><strong>说明</strong></td>
<td valign="top"><strong>对于的OMP的变量</strong></td>
</tr>
<tr>
<td valign="top"><strong>MKL_NUM_THREADS</strong></td>
<td valign="top">mkl_set_num_threads</td>
<td valign="top">建议MKL 函数使用的多线程的数目。.</td>
<td valign="top">OMP_NUM_THREADS</td>
</tr>
<tr>
<td valign="top"><strong>OMP_NUM_THREADS</strong></td>
<td valign="top">omp_set_num_threads</td>
<td valign="top">OpenMP提供的多线程设置的环境变量与API.</td>
<td valign="top"> </td>
</tr>
<tr>
<td valign="top"><strong>MKL_DYNAMIC</strong></td>
<td valign="top">mkl_set_dynamic</td>
<td valign="top">建议MKL根据计算问题，自动设置多线程的数目，线程数目不超过用户设定的线程的上限</td>
<td valign="top">OMP_DYNAMIC</td>
</tr>
</tbody>
</table>
<p> </p>
<p>需要说明的是，Intel MKL 提供的多线程设置的方法，优先级要高于OpenMP的方法。 比程序中，同时设置了下面的环境变量：<br />
&gt;export MKL_NUM_THREADS =1<br />
&gt;export OMP_NUM_THREADS =4<br />
此时，程序中，MKL的函数将会运行一个线程。</p>
<p>关于多线程的设置，我们还需要注意下面的3个问题：<br />
第一，在超线程的机器上，Intel MKL 多线程的设置：  在系统中，当多个线程的执行不同的操作，CPU有空闲资源时，多线程技术有较好的执行效果。Intel MKL的计算核心已经经过充分优化，并且这些计算的核心都执行类似的计算操作，所有多线程的设置，对于MKL 不能提供很好的帮助。 如果在程序执行的机器上， 超线程的设置已经打开， 一个推荐的做法是，设置MKL 的线程为系统核的数目（逻辑处理器数目的一半），并设置下面的threading affinity 的环境变量：<br />
  KMP_AFFINITY=granularity=fine,compact,1,0.</p>
<p>第二，MKL_DYNAMIC 环境变量： 这个环境变量确定是否由Intel MKL 来选择计算的线程的数目， 但是总的线程数不会超过MKL_NUM_THREADS与OMP_NUM_THREADS的值。 Intel MKL会根据实际计算问题的大小，以及多线程对计算是否有效等诸多情况，选择适合的线程数目，这也是缺省的Intel MKL 多线程设置方式。</p>
<p>如果用户手动设置MKL_DYNAMIC=FALSE， Intel MKL 将根据用户指定的线程数目，设置计算线程。 比如，设置： <br />
         MKL_DYNAMIC=FALSE<br />
         MKL_NUM_THREADS=6<br />
MKL函数将运行6个计算线程，尽管对某些小的计算问题，6个线程可能并不是最有效的。</p>
<p>第三，并不是所有MKL函数都是多线程。 某些计算函数，多线程并不能给程序带来性能提升，如Level 1 BLAS，其主要计算瓶颈是数据访问，这样的函数，内部多线程，不能带来很大帮助。 具体的MKL 多线程的函数列表， 可以查看用户手册。</p>
<p>有关多线程这方面的，进一步的参考文档：　<br />
MKL 用户手册：<a href="http://software.intel.com/sites/products/documentation/hpc/mkl/mkl_userguide_lnx/index.htm">http://software.intel.com/sites/products/documentation/hpc/mkl/mkl_userguide_lnx/index.htm</a><br />
相关文章：<br />
<a href="http://software.intel.com/en-us/forums/showthread.php?t=67622">http://software.intel.com/en-us/forums/showthread.php?t=67622</a><br />
<a href="http://software.intel.com/en-us/articles/intel-math-kernel-library-intel-mkl-intel-mkl-100-threading/">http://software.intel.com/en-us/articles/intel-math-kernel-library-intel-mkl-intel-mkl-100-threading/</a><br />
<a href="http://software.intel.com/en-us/articles/setting-thread-affinity-on-smt-or-ht-enabled-systems/">http://software.intel.com/en-us/articles/setting-thread-affinity-on-smt-or-ht-enabled-systems/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2012/03/20/intel-mkl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>一个游戏程序员的学习资料</title>
		<link>http://software.intel.com/zh-cn/blogs/2012/03/20/400010004/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2012/03/20/400010004/#comments</comments>
		<pubDate>Tue, 20 Mar 2012 05:29:48 +0000</pubDate>
		<dc:creator>weiqubo</dc:creator>
				<category><![CDATA[其他]]></category>
		<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[游戏]]></category>
		<category><![CDATA[软件开发工具]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2012/03/20/400010004/</guid>
		<description><![CDATA[  想起写这篇文章是在看侯杰先生的《深入浅出MFC》时, 突然觉得自己在大学这几年关于游戏编程方面还算是有些心得，因此写出这篇小文,介绍我眼中的游戏程序 员的书单与源代码参考。一则是作为自己今后两年学习目标的备忘录,二来没准对别人也有点参考价值。我的原则是只写自己研究过或准备研究的资料，所以内容无 疑会带上强烈的个人喜好色彩, 比如对网络,数据库等重要方面完全没有涉及。因为自己主要对三维图形引擎, 人工智能算法, 脚本系统, 反外挂 (反反外挂? ^－^)等方面感兴趣。这学期电脑都没联网了,在岳麓山闭关修炼中(^－^),连这篇文章都得在学校图书馆电子阅览室（电影放映室？）上传,内容很多凭记忆写出, 如有误差敬请订正。程序员应该在理论学习与实践编程中反复迭代，所以学习资料是一回事，须知尽信书不如无书。 一、书籍： 算法与数据结构： 《数据结构（C语言版）》——严蔚敏、吴伟民 清华出版社 我觉得其配套习题集甚至比原书更有价值，每个较难的题都值得做一下。 《Introduction to Algorithms》第二版 中文名《算法导论》 关 于算法的标准学习教材与工程参考手册，在去年CSDN网站上其翻译版竟然评为年度二十大技术畅销书，同时《程序员》杂志上开设了“算法擂台”栏目，这些溯 源固本的举动，不由得使人对中国现今浮躁不堪的所谓“IT”业又产生了一线希望。这本厚厚的书，幸亏打折我才买得起。虽然厚达千页，但其英文通俗晓畅，内 容深入浅出，可见经典之作往往比一般水准的书还耐读。还能找到MIT的视频教程，第一节课那个老教授嘻皮笑脸的，后面就是一长发助教上课了。 《C语言名题精选百则 技巧篇》——冼镜光 机械工业出版社 作 者花费一年时间搜集了各种常见C程序段的极具技巧性的编程法，其内容都是大有来头的，而且给出了详细的参考资料。如一个普通的Fibonacci数就给出 了非递归解、快速算法、扩充算法等，步步深入，直至几无油水可榨。对于视速度如生命，连一个普通的浮点数转化为整数都另辟蹊径以减少CPU cycle的游戏程序员，怎可不看？ 《计算机算法基础（第二版）》—— 佘祥宣等 华中科大出版社 我看到几个学校的研究生拿它作教材（研究生才开算法，太开玩笑了吧）。这本书薄是薄了点，用作者的话来说，倒也“精辟”。其实此书是《Fundamentals of Computer Algorithms》的缩写版，不过原书出版太久了，反正我是没找到。 《The Art of Computer Programming》Volume 1-3 作 者Donald E. Knuth是我心目中与冯.诺依曼、Dijkstra、Shannon并列的四位大师。这本书作者从读大学本科时开始写，一直写到博士时，十年磨一剑，足 见其下足了功夫。可作为计算机技术的核心——算法与数据结构的终极参考手册。创新处也颇多，譬如常见的Shell排序他在书中提出可用(3i-1)/2的 间隔，这使其稍快于O(n1. 5)。当然这套书描述高度数学化，为此恐怕一般的人（我？）最好还得先看一本数学预备书《Concrete Mathematics》（直译为混凝土数学？^－^）再说。可惜的是这套书才出到第三卷，并没有覆盖全部常见的算法内容。不过好在对于游戏程序员来说， 越常见的算法用得越多，这也不算是什么要命的损失。 《STL源码剖析》—— [...]]]></description>
			<content:encoded><![CDATA[<p> </p>
<p>想起写这篇文章是在看侯杰先生的《深入浅出MFC》时, 突然觉得自己在大学这几年关于游戏编程方面还算是有些心得，因此写出这篇小文,介绍我眼中的游戏程序 员的书单与源代码参考。一则是作为自己今后两年学习目标的备忘录,二来没准对别人也有点参考价值。我的原则是只写自己研究过或准备研究的资料，所以内容无 疑会带上强烈的个人喜好色彩, 比如对网络,数据库等重要方面完全没有涉及。因为自己主要对三维图形引擎, 人工智能算法, 脚本系统, 反外挂 (反反外挂? ^－^)等方面感兴趣。这学期电脑都没联网了,在岳麓山闭关修炼中(^－^),连这篇文章都得在学校图书馆电子阅览室（电影放映室？）上传,内容很多凭记忆写出, 如有误差敬请订正。程序员应该在理论学习与实践编程中反复迭代，所以学习资料是一回事，须知尽信书不如无书。</p>
<p>一、书籍：</p>
<p>算法与数据结构：</p>
<p>《数据结构（C语言版）》——严蔚敏、吴伟民 清华出版社</p>
<p>我觉得其配套习题集甚至比原书更有价值，每个较难的题都值得做一下。</p>
<p>《Introduction to Algorithms》第二版 中文名《算法导论》</p>
<p>关 于算法的标准学习教材与工程参考手册，在去年CSDN网站上其翻译版竟然评为年度二十大技术畅销书，同时《程序员》杂志上开设了“算法擂台”栏目，这些溯 源固本的举动，不由得使人对中国现今浮躁不堪的所谓“IT”业又产生了一线希望。这本厚厚的书，幸亏打折我才买得起。虽然厚达千页，但其英文通俗晓畅，内 容深入浅出，可见经典之作往往比一般水准的书还耐读。还能找到MIT的视频教程，第一节课那个老教授嘻皮笑脸的，后面就是一长发助教上课了。</p>
<p>《C语言名题精选百则 技巧篇》——冼镜光 机械工业出版社</p>
<p>作 者花费一年时间搜集了各种常见C程序段的极具技巧性的编程法，其内容都是大有来头的，而且给出了详细的参考资料。如一个普通的Fibonacci数就给出 了非递归解、快速算法、扩充算法等，步步深入，直至几无油水可榨。对于视速度如生命，连一个普通的浮点数转化为整数都另辟蹊径以减少CPU cycle的游戏程序员，怎可不看？</p>
<p>《计算机算法基础（第二版）》—— 佘祥宣等 华中科大出版社</p>
<p>我看到几个学校的研究生拿它作教材（研究生才开算法，太开玩笑了吧）。这本书薄是薄了点，用作者的话来说，倒也“精辟”。其实此书是《Fundamentals of Computer Algorithms》的缩写版，不过原书出版太久了，反正我是没找到。</p>
<p>《The Art of Computer Programming》Volume 1-3</p>
<p>作 者Donald E. Knuth是我心目中与冯.诺依曼、Dijkstra、Shannon并列的四位大师。这本书作者从读大学本科时开始写，一直写到博士时，十年磨一剑，足 见其下足了功夫。可作为计算机技术的核心——算法与数据结构的终极参考手册。创新处也颇多，譬如常见的Shell排序他在书中提出可用(3i-1)/2的 间隔，这使其稍快于O(n1. 5)。当然这套书描述高度数学化，为此恐怕一般的人（我？）最好还得先看一本数学预备书《Concrete Mathematics》（直译为混凝土数学？^－^）再说。可惜的是这套书才出到第三卷，并没有覆盖全部常见的算法内容。不过好在对于游戏程序员来说， 越常见的算法用得越多，这也不算是什么要命的损失。</p>
<p>《STL源码剖析》—— 侯捷 华中科大出版社</p>
<p>侯 捷不用介绍了，华人技术作家中的旗舰，说其有世界级水准也不为过。这本书我以为是C++与数据结构的葵花宝典（欲练此功，必先自宫）。也就是说，不下几层 地狱很难看懂，因为它要求的预备知识太多了，如STL、数据结构、泛型编程、内存管理都要很扎实（为此是不是还要看看有内存管理设计模式之称的 《Small Memory Software》这本书呢？），但是一旦看懂，真会是所向披靡。</p>
<p>《Data Structures for Game Programmers》</p>
<p>每个数据结构的例程都是一个小游戏，还用SDL库实现了一个算法演示系统。虽然内容失之于浅，但起码让人了解了数据结构在游戏中的作用。</p>
<p>其 实游戏程序并不比其它程序特殊，甚至要求基本功更加扎实，所以花时间做一些看似与实际应用不甚相干的习题，对今后的工作是大有裨益的。而且有些应用很广的 算法，如常被人津津乐道的A*算法及其变种，牵涉到图的检索周游与分枝-限界法，恐怕还得读一些艰深的论文才能充分明白运用，如Donald E. Knuth的《An analysis of alpha-beta cutoffs》。其实还有不少此类的好书，如《Data Structures and Algorithms in C++》、《Programming Pearls》、《More Programming Pearls》（算法珠玑）等，我却以为要先看严谨一点的著作，再看内容随笔一点的书。</p>
<p>汇编：</p>
<p>《IBM-PC 汇编语言程序设计》第二版</p>
<p>国内经典教材。</p>
<p>《The Art of Assembly Language》</p>
<p>这本书足有1600页，噢！</p>
<p>C语言：</p>
<p>《The C Programming Language》第二版</p>
<p>虽然篇幅短小，但每个例程都很经典。（我们老师开始拿它作教材，后面换为谭小强的C语言书，理由为：例子尽是些文本处理。我就纳了闷了，难道现代的计算机程序不是将大量时间消耗在字符串与文本的处理上吗？）</p>
<p>C++：</p>
<p>学过C语言，再学C++，先看这本《C++ Primer》的缩写版：</p>
<p>《Essential C++》</p>
<p>对C++有个入门了解，再看</p>
<p>《C++ Common Knowledge: Essential Intermediate Programming》</p>
<p>就不会有什么重要的知识点完全不知所措了，接下来是</p>
<p>《The C++ Standard Library : A Tutorial and Reference》</p>
<p>标准库，当然主要是标准模板库的标准学习参考手册，然后最好平时边写程序边参悟。</p>
<p>《Effective C++》等</p>
<p>我是说书名以形容词 + C++的那些书，计有七八本，慢慢看吧，罗马不是一日建成的。</p>
<p>(《Essential C++》、《Effective C++》、《More Effective C++》、《Accelerated C++》、《Effective STL》、《Exceptional C++》、《More Exceptional C++》、《Imperfect C++》，虽然书名格式相似，但每一本都绝非马虎之作。)</p>
<p>谁说C++程序比C程序要慢？那就请看下面：</p>
<p>《The Design and Evolution of C++》</p>
<p>知其过去才能知其未来，才能应用。</p>
<p>《Inside the C++ Object Model》</p>
<p>揭露C++的编译器模型。</p>
<p>《Efficient C++ Performance Programming Techniques》</p>
<p>当算法优化已到极致，在运用汇编之前，最后还可看看此书，有时高级和低阶都能做成相同的事情。</p>
<p>还有两本特别的书：</p>
<p>《Modern C++ Design : Generic Programming and Design Patterns Applied》</p>
<p>作者想把设计模式和泛型编程结合起来，并写了个尝试提供一切的Loki库来实作,不过其观点并未得到C++社区的普遍响应。尽管如此，本书仍称得上思想前沿性与技术实用性结合的典范。</p>
<p>《C++ Template Metaprogramming》</p>
<p>把 编译器当作计算器？本书介绍了Boost库的MPL模板元编程库。当然提到Boost库，对于游戏程序员不能不提到其中的Graph库，有《The Boost Graph Library》一书可看。还有其中Python库，号称国内首款商业三维图形引擎的起点引擎就用了Boost－Python库。说实话我觉得起点引擎还 是蛮不错的，那个自制的三维编辑器虽然界面简陋，但功能还算蛮完善，给游戏学院用作教学内容也不错。另有一个号称中国首款自主研发的全套网游解决方案。我 看到它那个三维编辑器，心想这不就是国外一个叫freeworld3D的编辑器吗？虽然有点偏门，但我以前还较劲尝试破解过呢。还把英文界面汉化了，大概 用exescope这样的资源修改软件就能搞定吧。我又心想为什么要找freeworld3D这个功能并不太强大的编辑器呢？仅仅是因为它便宜到几十美 金？它唯一特别一点的地方就是支持导出OGRE图形引擎的场景格式，这样一想不由得使人对它图形引擎的“自主”性也产生怀疑了。这样的“自主”研发真让人 汗颜，只要中国还没封sourceforge这个网站（据说以前和freeBSD网站一起被封过？），国人就能“自主”研发。</p>
<p>有人还会推荐《C++ Primer》《Thinking in C++》《The C++ Programming Language》等书吧，诚然这些书也很好，但我总觉得它们太大部头了。还不如多花点时间看看国外好的源代码。</p>
<p>Windows编程</p>
<p>《Operating System Concepts》第五版</p>
<p>国内有些操作系统的教程其实就是它的缩写版。</p>
<p>《Windows 95 System Programming Secrets》</p>
<p>深入剖析了Windows操作系统的种种种种，有人爱看《Linux内核完全注释》，有人爱看《自己动手写操作系统》这样煽情的书，但我想作为商业的操作系统，把Windows内核剖析到这地步也高山仰止了。</p>
<p>《Programming Applications for Microsoft Windows》第四版</p>
<p>先进程线程，再虚存管理，再动态链接库，最多讲到消息机制。作者在序言中说：“我不讲什么ActiveX, COM等等，因为当你了解了这些基础后，那些东西很快就会明白！”可以作为《Programming Windows》的先修课。</p>
<p>计算机体系：</p>
<p>《Computer Systems : A Programmer’s Perspective》</p>
<p>和《The Art of Computer Programming》在我心中是计算机史上两本称得上伟大的书，计算机组成原理，操作系统，汇编，编译原理，计算机网络等等课程汇成这本千页的大书，因为计算机在作者眼中就是一个整体。</p>
<p>开源阅读：</p>
<p>《Code Reading : The Open Source Perspective》</p>
<p>张大千临摹了几百张明代石涛的山水，画出的画以假乱真，后来他去敦煌潜心临摹几年，回来画风大变，终成大家。程序员其实有4 0%的时间是在读别人的源代码，侯捷先生说：“源码面前，了无秘密”，又说“天下大事，必作于细”，可以与他的《上穷碧落下黄泉，源码追踪经验谈》参看。</p>
<p>MFC:</p>
<p>《深入浅出MFC》</p>
<p>我 实在以为没有看过侯捷先生的《深入浅出MFC》的人多半不会懂得MFC编程。其实我是打算用一年多的时间写一个给游戏美工用的三维编辑器，顺便作为毕业设 计。图形库就用MFC吧，反正也没得选择。如果要用wxWidgets无非是猎奇而已，还不是MFC的翻版，当然它跨平台了。就象阻击手对自己枪械的零件 了如指掌一样，要想用MFC写出非玩具程序的人一定要了解其内部构造。还有一本书叫《MFC深入浅出》，并不是同一本。</p>
<p>IDE:</p>
<p>《Microsoft Visual Studio 2005 Unleashed》</p>
<p>工欲善其事，必先利其器。当然我认为与其用形如Source Insight、Slick Edit、Code Visualizer之类的代码阅读器、图形化工具，还不如用自己的大脑。但如果你嫌打源代码慢的话，可以用Visual AssistX。如果嫌老是写重复相似的代码的话，可以用Code Smith。单元测试可以用CppUnit，Boost库中的测试框架也不错。有心情可以吧Visual Studio外接Intel的Compiler，内嵌STLport，但不是大工程，性能分析没必要动不动就用下VTune吧。</p>
<p>程序员之路：</p>
<p>《游戏之旅——我的编程感悟》(#add不怎么样)</p>
<p>云 风大哥。在我心目中游戏程序员国外首推卡马克，国内首推云风。也许过两年我会到网易当云风大哥的助理程序员吧。It’s my dream.（^-^）他写这本书的时候本着只有透彻理解的东西才写出来，因此内容不会很酷新，但是相信我，每读一遍都有新的收获，主要还不是知识上的， 因为知识是学无止境的，授人以鱼不如授人以渔，精神上的启迪才是长久的。诚如经典游戏《 仙剑 奇侠传》的主力程序员兼美术指导姚壮宪（人称姚仙）在序言中所说的“云风得到的只是一些稿费，而整个中国民族游戏产业得到的将是一次知识的推动”，此言不虚矣。</p>
<p>《编程高手箴言》(#add差)</p>
<p>梁 肇新是豪杰超级解霸的作者，本来每个合格的程序员（Programmer , 而非Coder）都应该掌握的东西，现在变成了编程高手的独家箴言。不知是作者的幸运还是中国IT业的悲哀。知识点还是讲得蛮多的，不过对MFC的地位颇 有微词。我实在认为MFC的名声就是那些不懂得用它的人搞臭的。不过作者的牢骚也情有可原，每个具有创造力的程序员都应该不太喜欢framework。</p>
<p>《Masters of DOOM: How Two Guys Created an Empire and Transformed Pop Culture》中文名《DOOM启世录》</p>
<p>卡 马克，罗洛斯，这些游戏史上如雷贯耳的名字。（现在卡马克已专注于火箭制造上，罗洛斯则携妻回乡隐居）要不是没上过大学的卡马克和图形学大师亚伯拉罕的功 勋，可能到现在游戏中还不知三维为何物。勿庸置疑，在计算机界历史是英雄们所推动的。这本书真实的记录了这些尘世英雄的所为所思。</p>
<p>作为程序员的我对这几本策划与美工的书也产生了浓厚兴趣，以前搞过一两年的3DS MAX插件编程，觉得用maxscript还是好过MaxSDK，毕竟游戏开发中所多的是模型场景数据的导入导出，大可不必大动干戈。</p>
<p>策划：</p>
<p>《Creating Emotion in Games : The Craft and Art of Emotioneering》</p>
<p>在壮丽煊目的宏伟三维世界背后，在残酷的杀戮，动人心魄的情节背后，我们还需要什么来抓住玩家的心？答对了，就是emotion.真正打动人心的，才是深入骨髓的。</p>
<p>《Ultimate Game Design : Building Game Worlds》</p>
<p>从名字可以看出，写给关卡设计师的，特别是讲室外自然场景的构建颇有可取之处。</p>
<p>《Developing Online Games : An Insider’s Guide》</p>
<p>就象名为反模式的书讲软件团队运营一样，这本书讲商业运作多过技术。一个历经艰难，现在盛大的游戏程序员，翻译了这本书。<br />
美工：</p>
<p>《Digital Cinematography &amp; Directing》</p>
<p>数字摄影导演术，每当你在3DS MAX或者Maya等三维创作软件中摆放摄影机，设计其运动轨迹时，你可曾想过你也站在导演的位置上了？</p>
<p>《The Animator’s Survival Kit》</p>
<p>看 着这本讲卡通角色运动规律的书，一边产生温习《猫和老鼠》的念头，一边继续对前不久新闻联播中关于中国产生了某计算机自动卡通动画生成软件报道的蔑视，这 条报道称此举可大大加快中国卡通动画的产量。我且不从技术上探讨其是否是在放卫星（其实我知道得很清楚，前文已表，本人搞过一两年的卡通动画辅助软件编 程），但计算机机械生成的动画怎可代替人类充满灵性的创作？</p>
<p>《The Dark Side of Game Texturing》</p>
<p>用Photoshop制作材质贴图，还真有些学问。</p>
<p>三维图形学：</p>
<p>搞三维图形学首先还是要扎扎实实的先看解析几何、线性代数、计算几何的教材，后面的习题一个都不能少。国内数学书还是蛮好的。苏步青大师的《计算几何》称得上具有世界级水准，可惜中国CAD的宏图被盗版给击垮了。现在是我们接过接力棒的时候了。It’s time!</p>
<p>《Computer Graphics Geometrical Tools》</p>
<p>《计算机图形学几何工具算法详解》算法很多，纰漏处也不少。</p>
<p>《3D Math Primer for Graphics and Game Development》</p>
<p>浅易，可作为三维数学的“速食“。</p>
<p>《Mathematics for 3D Game Programming &amp; Computer Graphics》第二版</p>
<p>比上面那本深入一些，证明推理的数学气也浓一些，可作为专业的数学书与编程实践一个过渡的桥梁吧。内容涉猎也广，射线追踪，光照计算，可视裁剪，碰撞检测，多边形技术，阴影算法，刚体物理，流体水波，数值方法，曲线曲面，还真够丰富。</p>
<p>《Vector Game Math Processors》</p>
<p>想学MMX,SSE吗，那就看它吧，不过从基础讲起的，要耐心哦。</p>
<p>DirectX:</p>
<p>《Introduction to 3D Game Programming with DirectX 9.0》</p>
<p>DirectX入门的龙书，作者自己写的简单示例框架，后面我干脆用State模式，把所有例子绑到一块儿去了。</p>
<p>《Beginning Direct3D Game Programming》</p>
<p>作 者取得律师学位后变成了游戏程序员，真是怪也哉。本书虽定位为入门级书，内容颇有独特可取之处。它用到的示例框架是DXSDK Sample Framework，而不是现在通行的DXUT。要想编译有两种办法吧，一是自己改写成用DXUT的。二是找旧的Sample Framework。我又懒得为了一个示例框架下载整个早期版本的DirectX，后面在Nvidia SDK 9.5中发现了。</p>
<p>《Advanced Animation with DirectX》</p>
<p>DirectX 高级动画技术。骨骼系统，渐变关键帧动画，偶人技术，表情变形，粒子系统，布料柔体，动态材质，不一而足。我常常在想，从三维创作软件导出的种种效果，变 成一堆text或binary，先加密压缩打包再解包解压解密，再用游戏程序重建一个Lite动画系统，游戏程序员也真是辛苦。</p>
<p>OpenGL:</p>
<p>《NeHe OpenGL Tutorials》</p>
<p>虽是网络教程，不比正式的书逊，本来学OpenGL就不过是看百来条C函数文档的工夫吧,如果图形学基础知识扎实的话。</p>
<p>《OpenGL Shading Language》</p>
<p>OpenGL支持最新显卡技术要靠修修补补的插件扩展，所以还要配合</p>
<p>《Nvidia OpenGL Extension Specifications》</p>
<p>来看为上。</p>
<p>《Focus on 3D Models》</p>
<p>《Focus on 3D Terrain Programming》</p>
<p>《Focus on Curves and Surfaces》</p>
<p>顾名思义，三本专论，虽然都很不深，但要对未知三维模型格式作反向工程前，研读Geomipmapping地形算法论文前，CAD前，还是要看看它们为上，如果没从别处得过到基础的话。</p>
<p>脚本：</p>
<p>先看</p>
<p>《Game Scripting Mastery》</p>
<p>等自己了解了虚拟机的构造，可以设计出简单的脚本解释执行系统了。</p>
<p>再去查Python , Lua ，Ruby的手册吧，会事半半功倍倍的。</p>
<p>《Programming Role Playing Games with DirectX 8.0》</p>
<p>一边教学一边用DirectX写出了一个GameCore库，初具引擎稚形。</p>
<p>《Isometric Game Programming with DirectX 7.0》</p>
<p>三维也是建立在二维的基础上，这就是这本书现在还值得看的原因。</p>
<p>《Visual C++网络游戏建模与实现》</p>
<p>联众的程序员写的，功力很扎实，讲棋牌类游戏编程，特别讲了UML建模和Rotional Rose。</p>
<p>《Object-Oriented Game Development》</p>
<p>套用某人的话：“I like this book.”</p>
<p>Shader:</p>
<p>要入门可先看</p>
<p>《Shaders for Game Programmers and Artists》</p>
<p>讲在RenderMonkey中用HLSL高级着色语言写Shader.</p>
<p>再看</p>
<p>《Direct3D ShaderX : Vertex and Pixel Shander Tips and Tricks》</p>
<p>用汇编着色语言，纯银赤金。</p>
<p>三大宝库：</p>
<p>《Game Programming Gems》</p>
<p>我只见到1-6本，据说第7、8本也出来了？附带的源代码常有bug，不过瑕不掩瑜，这套世界顶级游戏程序员每年一度的技术文集，涉及游戏开发的各个方面，我觉得富有开发经验的人更能在其中找到共鸣。</p>
<p>《Graphics Gems》全五本</p>
<p>图形学编程Bible，看了这套书你会明白计算机领域的科学家和工程师区别之所在。科学家总是说，这个东西在理论上可行。工程师会说，要使问题在logN的时限内解决我只能忍痛割爱，舍繁趋简。</p>
<p>《GPU Gems》出了二本</p>
<p>Nvidia公司召集图形学Gurus写的，等到看懂的那一天，我也有心情跑去Siggraph国际图形学大会上投文章碰运气。</p>
<p>游戏引擎编程：</p>
<p>《3D Game Engine Programming》</p>
<p>是ZFXEngine引擎的设计思路阐释，很平实，冇太多惊喜。</p>
<p>《3D Game Engine Design》</p>
<p>数学物理的理论知识讲解较多，本来这样就够了，还能期待更多吗？</p>
<p>人工智能：</p>
<p>《AI Techniques for Game Programming》</p>
<p>讲遗传算法，人工神经网络，主要用到位数组，图算法。书的原型是根据作者发表到GameDev.net论坛上的内容整理出来的，还比较切中实际。</p>
<p>《AI Game Programming Wisdom》</p>
<p>相当于AI编程的Gems。</p>
<p>《PC游戏编程(人机博弈)》</p>
<p>以 象棋程序为蓝本，介绍了很多种搜索算法，除了常见的极大极小值算法及其改进--负极大值算法，还有深度优先搜索以外。更提供了多种改进算法， 如：Alpha-Beta,Fail-soft alpha-beta,Aspiration Search, Minimal Window Search,Zobrist Hash,Iterative Deepening,History Heuristic,Killer Heuristic,SSS*,DUAL*,MFD and more.琳琅满目，实属难得。</p>
<p>反外挂：</p>
<p>《加密与解密(第二版)》 看雪论坛站长 段钢</p>
<p>破解序列号与反外挂有关系么？不过，世上哪两件事情之间又没有关系呢？</p>
<p>《UML Distilled》 Martin Fowler</p>
<p>很多人直到看了这本书才真正学懂UML。</p>
<p>Martin Fowler是真正的大师,从早期的分析模式,到这本UML精粹,革命性的重构都是他提出的,后来又写了企业模式一书。现在领导一个软件开发咨询公司，去年JavaOne中国大会他作为专家来华了吧。个人网站：MartinFowler.com</p>
<p>设计模式三剑客：</p>
<p>《Design Patterns Elements of Reusable Object-Oriented Software》</p>
<p>《Design Patterns Explained》</p>
<p>《Head First Design Patterns》</p>
<p>重构三板斧：</p>
<p>《Refactoring : Improving the Design of Existing Code》</p>
<p>《Refactoring to Patterns》</p>
<p>《Refactoring Workbook》</p>
<p>软件工程:</p>
<p>《Extreme Programming Explained : Embrace Change》第二版</p>
<p>其中Simplicity的Value真是振聋发聩，这就是我什么都喜欢轻量级的原因。</p>
<p>《Agile Software Development Principles,Patterns,and Practices》</p>
<p>敏捷真是炒得够火的，连企业都有敏捷一说，不过大师是不会这么advertising的。</p>
<p>《Code Complete》第二版</p>
<p>名著。</p>
<p>数学：</p>
<p>《数学，确定性的丧失》M.克莱因</p>
<p>原来数学也只不过是人类的发明与臆造，用不着供入神殿，想起历史上那么多不食人间烟火的科学家（多半是数学家），自以为发现了宇宙运作的奥秘，是时候走下神坛了。</p>
<p>物理：</p>
<p>《普通物理学》第一册 += 《Physics for Game Developers》</p>
<p>物理我想就到此为此吧，再复杂我可要用Newton Engine,ODE了，等待物理卡PPU普及的那天，就可充分发挥PhysX的功效了，看过最新的《细胞分裂》游戏Demo演示，成千上万个Box疯狂Collide，骨灰级玩家该一边摸钱包一边流口水了。</p>
<p>二、开源代码：</p>
<p>Irrlicht</p>
<p>著 名的鬼火引擎，从两年前第一眼看到它，这个轻量级的三维图形引擎，就喜欢上了它。源代码优雅，高效，且不故弄玄虚。值得每个C++程序员一读，并不限于图 形编程者。它的周边中也有不少轻量级的东西。如Lightfeather扩展引擎，ICE、IrrlichtRPG、IrrWizard.还有 IrrEdit、IrrKlang、IrrXML可用。（可能是为了效率原因，很多开源作者往往喜欢自己写XML解析库，如以上的IrrXML库,即使有现成的tinyXML库可用。这真会让tomcat里面塞Axis，Axis里面塞JUDDI，弄得像俄罗斯套娃玩具的Java Web Service Coder们汗颜。）</p>
<p>OGRE</p>
<p>排 名第一的开源图形引擎，当然规模是很大的，周边也很多。除了以C#写就的OgreStudio ，ofusion嵌入3DS MAX作为WYSWYG式的三维编辑器也是棒棒的，特别是其几个场景、地形插件值得研究。以至于《Pro OGRE 3D Programming》一书专论其用法。搜狐的《天龙八部》游戏就是以其作为图形引擎，当然还另外开发了引擎插块啦。我早知道OGRE开发组中有一个中 国人谢程序员，他以前做了很多年的传统软件编程。有一次天龙八部游戏的图形模块的出错信息中包含了一串某程序员的工作目录，有一个文件夹名即是谢程序员的 英文名，我据此推断谢程序员即是搜狐北京的主程。看来中国对开源事业还是有所贡献的嘛，王开源哥哥的努力看来不会白费！（^-^）不过我侦测的手法也有些 像网站数据库爆库了，非君子之所为作。</p>
<p>RakNet</p>
<p>基于UDI的网络库，竟还支持声音传输，以后和OpenVision结合起来做个视聊程序试试。</p>
<p>Blender</p>
<p>声誉最盛的开源三维动画软件，竟还带一个游戏引擎。虽然操作以快捷键驱动，也就是说要背上百来个快捷键才能熟练使用。但是作为从商业代码变为开源之作，威胁三维商业巨头的轻骑兵，历经十年锤炼，代码达百万行，此代码只应天上有，人间哪得几回看，怎可不作为长期的源码参考？</p>
<p>风魂</p>
<p>二维图形库。云风大哥的成名之作。虽然不代表其最高水平（最高水平作为商业代码保存在广州网易互动的SVN里呢），但是也可以一仰风采了。</p>
<p>圣剑英雄传</p>
<p>二 维RPG。几个作者已成为成都锦天的主力程序员。锦天的老总从一百万发家，三年时间身价过亿，也是一代枭雄了。这份代码作为几年前的学生作品也算可以了， 因为一个工程讲究的是四平八稳，并不一定要哪个模块多么出彩。反正我是没有时间写这么一个东东，连个美工都找不到，只能整天想着破解别人的资源（^- ^）。</p>
<p>Boost</p>
<p>C++准标准库，我想更多的时候可以参考学习其源代码。</p>
<p>Yake</p>
<p>我 遇到的最好的轻量级游戏框架了。在以前把一个工程中的图形引擎从Irrlicht换成OGRE的尝试中，遇到了它。OGRE的周边工程在我看来都很庸肿， 没有完善文档的情况下看起来和Linux内核差不多。不过这个Yake引擎倒是很喜欢。它以一个FSM有限状态机作为实时程序的调度核心，然后每个模块： 物理、图形、网络、脚本、GUI、输入等等都提供一个接口，接口之下再提供到每种具体开源引擎的接口，然后再接具体引擎。通过这样层层抽象，此时你是接 Newton Engine,ODE还是PysX都可以；是接OGRE,Crystal Space还是Irrlicht都可以；是接RakNet还是LibCurl都可以；是接Python，Lua还是Ruby都可以，是接CEGUI还是 others，是接OIS还是others（呵呵,记不起来others）都可以。所以Yake本质上不是OGRE的周边。虽然用Neoengine的人 都倒向了它，但是现在版本还很早。特别是我认为，学习研究时一定要有这种抽象之抽象，接口之接口的东西把思维从具体的绑定打开，而开发时抽象要有限度的， 就像蔡学镛在《Java夜未眠》中讲的，面向对象用得过滥也会得OOOO症(面向对象过敏强迫症)。</p>
<p>Quake Doom系列</p>
<p>据说很经典，卡马克这种开源的黑客精神就值得赞许。把商业源代码放出来，走自己的创新之路，让别人追去吧。不过Quake与Unreal引擎的三维编辑器是现在所有编辑器的鼻祖，看来要好好看看了。</p>
<p>Nvidia SDK 9.X</p>
<p>三 维图形编程的大宝库，这些Diret3D与OpenGL的示例程序都是用来展示其最新的显卡技术的。硬件厂商往往对软件产品不甚在意，源代码给你看,东西 给你用去吧，学完了还得买我的硬件。Intel的编译器，PhysX物理引擎大概也都是这样。Havok会把它的Havok物理引擎免费给别人用吗？别说 试用版，连个Demo都看不到。所以这套SDK的内容可比MS DirectX SDK里面那些入门级的示例酷多了，反正我是如获至宝，三月不知愁滋味。不过显卡要so-so哦。我的GeForce 6600有两三个跑不过去,差强人意。</p>
<p>三、网站：</p>
<p>www.CSDN.net</p>
<p>程序员大本营吧，软文与“新技术秀”讨厌了点，blog和社区是精华之所在。</p>
<p>www.GameRes.com</p>
<p>游戏程序员基地，文档库中还有点东西。投稿的接收者Seabug与圣剑英雄传的主程Seabug会是同一个人吗？一个在成都锦天担当技术重担的高手还有时间维护网站吗？我不得而知。</p>
<p>“何苦做游戏”网站</p>
<p>名字很个性，站长也是历尽几年前产业发展初期的艰难才出此名字。</p>
<p>www.66rpg.com</p>
<p>二维游戏图片资源很多，站长柳柳主推的RPGMaker 软件也可以玩一玩吧，但对于专业开发者来说不可当真。</p>
<p>www.GameDev.net</p>
<p>论坛中有不少热心的国外高手在活动。</p>
<p>www.SourceForge.net</p>
<p>不用说了，世界最大的开源代码库，入金山怎可空手而返？看到国外那些学生项目动不动就像模像样的。（DirectX的稚形就是英国的学生项目，在学校还被判为不合格。）</p>
<p>www.koders.com</p>
<p>源 代码搜索引擎,支持正则表达式,google Lab中也有。当你某种功能写不出来时,可以看一下开源代码怎么写的,当然不过是仅供参考,开源代码未必都有产品级的强度。说到google,可看 《Google Power Tools Bible》一书，你会发现，google的众多产品原来也有这么多使用门道。</p>
<p>这篇小文足足写了一天半的时间，不由得使我对侯捷一样的技术作家长期伏案辛勤劳作深深敬佩了。看来对于书籍或者软件，都应该尊重作者或者programmer的才智劳动。</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2012/03/20/400010004/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Intel(R) Optimized LINPACK Benchmark 性能测试</title>
		<link>http://software.intel.com/zh-cn/blogs/2012/02/23/intelr-optimized-linpack-benchmark/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2012/02/23/intelr-optimized-linpack-benchmark/#comments</comments>
		<pubDate>Thu, 23 Feb 2012 02:50:59 +0000</pubDate>
		<dc:creator>Chao Y (Intel)</dc:creator>
				<category><![CDATA[其他]]></category>
		<category><![CDATA[并行计算]]></category>
		<category><![CDATA[软件开发工具]]></category>
		<category><![CDATA[Intel MKL]]></category>
		<category><![CDATA[LINPACK]]></category>
		<category><![CDATA[LINPACK Benchmark]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2012/02/23/intelr-optimized-linpack-benchmark/</guid>
		<description><![CDATA[Linpack是我们常用的CPU性能测试程序。它通过计算双精度线性方程组的求解来测试CPU的运算能力。Intel MKL提供一个优化版本的Intel(R) Optimized LINPACK Benchmark，通过运行这个程序，我们可以方便进行CPU的基准性能测试。 Intel(R) Optimized LINPACK Benchmark是根据LINPACK 1000 benchmark优化后的程序。程序根据用户指定的参数生成一个线性的方程组，通过方程的求解时间与计算量，来计算CPU的浮点性能。  运行这个程序基本步骤为： 1&#62;Intel(R) Optimized LINPACK Benchmark 下载： Intel(R) Optimized LINPACK Benchmark程序包括在Intel MKL 安装包中。如果已经下载并且安装了Intel MKL(http://www3.intel.com/cd/software/products/apac/zho/329191.htm ), LINPACK Benchmark 位于 mkl/benchmarks/linpack 目录下。 Intel(R) Optimized LINPACK Benchmark，还提供的单独下载：http://software.intel.com/en-us/articles/intel-math-kernel-library-linpack-download/  2&#62;程序运行： benchmarks/linpack目录下，包括了已经编译好的可执行文件。直接运行该程序，就可以进行相应的性能测试。运行程序前，建议首先阅读MKL用户指南中，有关“LINPACK and MP LINPACK Benchmarks”的说明部分： http://software.intel.com/sites/products/documentation/hpc/composerxe/en-us/mklxe/mkl_userguide_win/MKL_UG_linpack/MKL_UG_linpack.htm 在Intel 64 的平台上， 一个简单的运行命令如下：   &#62;./xlinpack_xeon64 lininput_xeon64 程序运行后，会提供如下图类似的性能数据： 其中GFlops 列提供了方程求解时， 每秒系统能计算到多少次的10亿次双精度浮点运算(GFLOPs)。比如，我们在Intel(R) Core(TM) i7-2600K CPU @ [...]]]></description>
			<content:encoded><![CDATA[<p>Linpack是我们常用的CPU性能测试程序。它通过计算双精度线性方程组的求解来测试CPU的运算能力。Intel MKL提供一个优化版本的Intel(R) Optimized LINPACK Benchmark，通过运行这个程序，我们可以方便进行CPU的基准性能测试。</p>
<p>Intel(R) Optimized LINPACK Benchmark是根据LINPACK 1000 benchmark优化后的程序。程序根据用户指定的参数生成一个线性的方程组，通过方程的求解时间与计算量，来计算CPU的浮点性能。 </p>
<p>运行这个程序基本步骤为：</p>
<p><strong>1&gt;Intel(R) Optimized LINPACK Benchmark 下载：</strong></p>
<p>Intel(R) Optimized LINPACK Benchmark程序包括在Intel MKL 安装包中。如果已经下载并且安装了Intel MKL(http://www3.intel.com/cd/software/products/apac/zho/329191.htm ), LINPACK Benchmark 位于 mkl/benchmarks/linpack 目录下。</p>
<p>Intel(R) Optimized LINPACK Benchmark，还提供的单独下载：<a href="http://software.intel.com/en-us/articles/intel-math-kernel-library-linpack-download/">http://software.intel.com/en-us/articles/intel-math-kernel-library-linpack-download/</a></p>
<p> <strong>2&gt;程序运行：</strong></p>
<p>benchmarks/linpack目录下，包括了已经编译好的可执行文件。直接运行该程序，就可以进行相应的性能测试。运行程序前，建议首先阅读MKL用户指南中，有关“LINPACK and MP LINPACK Benchmarks”的说明部分：</p>
<p><a href="http://software.intel.com/sites/products/documentation/hpc/composerxe/en-us/mklxe/mkl_userguide_win/MKL_UG_linpack/MKL_UG_linpack.htm">http://software.intel.com/sites/products/documentation/hpc/composerxe/en-us/mklxe/mkl_userguide_win/MKL_UG_linpack/MKL_UG_linpack.htm</a></p>
<p>在Intel 64 的平台上， 一个简单的运行命令如下：</p>
<p>  &gt;./xlinpack_xeon64 lininput_xeon64</p>
<p>程序运行后，会提供如下图类似的性能数据： 其中GFlops 列提供了方程求解时， 每秒系统能计算到多少次的10亿次双精度浮点运算(GFLOPs)。比如，我们在Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz，4 核的机器测试的结果中，够达到93GFlops 运行结果，该CPU双精度的理论峰值为108.8GFLPs，说明测试程序达到86%的理论峰值。</p>
<p><a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/Untitled.jpg"><img class="alignnone size-full wp-image-400009867" src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/Untitled.jpg" alt="" width="557" height="211" /></a></p>
<p> <strong>3&gt;运行参数</strong></p>
<p>运行该程序，需要输入参数文件。 该文件包括了运行LINPACK 程序的主要参数。填写参数时，一些主要的注意事项为：</p>
<p> 1）设置测试矩阵维数时，需同时考虑的内存的大小：程序运行中，会提示出所需内存（Maximum memory requested that can be used =...), 如果系统实际内存小于该值，需要减小输入的矩阵的维数。</p>
<p>2）矩阵行间距（Leading dimension of array）：矩阵行间距必须大于或等于矩阵大小。实际运行时，可以根据具体的环境，测试一下能取得最好性能的矩阵行间距大小。一些测试经验表明，行间距常常在大于矩阵的维数，并能够被8 整除的长度时，系统能取得较高性能。</p>
<p>3）数据的对齐值（alignment values）：该数据是KB为单位的，如缺省的输入数据是4，表示是以4K的内存地址上对齐。通常，我们可以将对齐值设置为系统页面的大小。</p>
<p><strong>4&gt;多线程设置</strong></p>
<p>该程序是一个多核优化后的程序. 缺省的程序会根据系统处理器核的数目，设置线程. 用户可以通过OMP_NUM_THREADS 来改变程序运行的线程数目. 如在bash shell中, 设置：</p>
<p>      &gt;export  OMP_NUM_THRADS= 线程数目</p>
<p>为获得最高性能，将线程数目设置为系统核的数目。在有超线程的系统中，设置该数目为系统超线程数目的一半，并设置下面的环境变量：</p>
<p>      KMP_AFFINITY=granularity=fine,compact,1,0.</p>
<p>这方面的讨论，可以参考文章： <a href="http://software.intel.com/en-us/articles/setting-thread-affinity-on-smt-or-ht-enabled-systems/">http://software.intel.com/en-us/articles/setting-thread-affinity-on-smt-or-ht-enabled-systems/</a></p>
<p>最后需要顺便说明的是，这个程序的结果，不适用于提交为LINPACK 1000 性能数据。该基准测试需要，运行编译器直接编译后的代码。Intel(R) Optimized LINPACK Benchmark包括手工专门针对处理器优化的代码。</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2012/02/23/intelr-optimized-linpack-benchmark/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>移动Web应用程序开发HTML5篇 (三) Canvas API</title>
		<link>http://software.intel.com/zh-cn/blogs/2012/02/22/webhtml5-canvas-api/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2012/02/22/webhtml5-canvas-api/#comments</comments>
		<pubDate>Wed, 22 Feb 2012 05:52:06 +0000</pubDate>
		<dc:creator>Dawei Cheng 程大伟 (Intel)</dc:creator>
				<category><![CDATA[全国大学生软件创新大赛专栏]]></category>
		<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[移动技术]]></category>
		<category><![CDATA[英特尔® 软件网络 2.0]]></category>
		<category><![CDATA[软件开发工具]]></category>
		<category><![CDATA[软件技术学习及认证]]></category>
		<category><![CDATA[Canvas]]></category>
		<category><![CDATA[HTML5]]></category>
		<category><![CDATA[Web应用开发]]></category>
		<category><![CDATA[移动开发]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2012/02/22/webhtml5-canvas-api/</guid>
		<description><![CDATA[介绍 本系列博客将主要介绍如今大红大紫的移动Web应用程序开发最重要的三个工具：HTML5，JavaScript， CSS3。 本篇是HTML5介绍的第三篇，主要介绍HTML5的Canvas API。 相关文章： 移动Web应用程序开发 HTML5篇 (一) HTML5简介 移动Web应用程序开发 HTML5篇 (二) 新功能介绍和测试 •1. Canvas API介绍 &#60;canvas&#62;是HTML5引入的一个新的元素，可以使用JavaScript来绘制图形、合成图象、以及做一些动画。&#60;canvas&#62;最先出现在Apple Mac OS X Dashboard中，也被应用于Safari，随着后来基于Gecko1.8的浏览器Firefox 1.5的加入变得流行起来，目前&#60;canvas&#62;是HTML 5标准规范的一部分。目前最新版本的主流浏览器都支持&#60;canvas&#62;，支持情况如下图： •2. Canvas 入门 一个简单的Canvas例子，代码如下： &#60;!DOCTYPE HTML&#62; &#60;html&#62; &#60;canvas id="diagonal" style="border: 1px solid;" width="200" height="200"&#62; &#60;/canvas&#62; &#60;/html&#62; &#60;script&#62; function drawDiagonal() { // Get the canvas element and its drawing context var canvas [...]]]></description>
			<content:encoded><![CDATA[<div><strong>介绍</strong><strong> </strong></div>
<div>本系列博客将主要介绍如今大红大紫的移动Web应用程序开发最重要的三个工具：HTML5，JavaScript， CSS3。</div>
<div>本篇是HTML5介绍的第三篇，主要介绍HTML5的Canvas API。</div>
<div>相关文章：</div>
<div><a href="http://software.intel.com/zh-cn/blogs/2012/02/20/web-html5-html5/">移动Web应用程序开发 HTML5篇 (一) HTML5简介 </a></div>
<div><a href="http://software.intel.com/zh-cn/blogs/2012/02/22/web-html5/">移动Web应用程序开发 HTML5篇 (二) 新功能介绍和测试</a></div>
<div><a name="OLE_LINK23"></a><a name="OLE_LINK22"><strong>•1. </strong><strong>Canvas API</strong></a><strong>介绍</strong><strong></strong></div>
<div>&lt;canvas&gt;是HTML5引入的一个新的元素，可以使用JavaScript来绘制图形、合成图象、以及做一些动画。&lt;canvas&gt;最先出现在Apple Mac OS X Dashboard中，也被应用于Safari，随着后来基于Gecko1.8的浏览器Firefox 1.5的加入变得流行起来，目前<a name="OLE_LINK21"></a><a name="OLE_LINK20">&lt;canvas&gt;</a>是HTML 5标准规范的一部分。目前最新版本的主流浏览器都支持&lt;canvas&gt;，支持情况如下图：</div>
<div><img src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/31.jpg" alt="" width="377" height="104" /></div>
<div><a name="OLE_LINK25"></a><a name="OLE_LINK24"><strong>•2. </strong><strong>Canvas </strong></a><strong>入门</strong><strong></strong></div>
<div>一个简单的Canvas例子，代码如下：</div>
<pre name="code" class="xhtml">&lt;!DOCTYPE HTML&gt;

&lt;html&gt;

&lt;canvas id="diagonal" style="border: 1px solid;" width="200" height="200"&gt;
&lt;/canvas&gt;
&lt;/html&gt;
&lt;script&gt;
function drawDiagonal() {
// Get the canvas element and its drawing context
var canvas = document.getElementById('diagonal');
var context = canvas.getContext('2d');
// Create a path in absolute coordinates
context.beginPath();
context.moveTo(100, 140);
context.lineTo(140, 70);
// Stroke the line onto the canvas
context.stroke();
}
window.addEventListener("load", drawDiagonal, true);
&lt;/script&gt;</pre>
<div>代码运行效果如图，通过绝对坐标画出一条线：</div>
<div><img src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/32.jpg" alt="" width="182" height="186" /></div>
<div>Canvas把整个画布用坐标值进行了表示，左上角为（0，0），依次沿着X轴和Y轴延伸。坐标图如下所示：</div>
<div><img src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/33.jpg" alt="" width="301" height="303" /></div>
<div>再看一个例子：</div>
<pre name="code" class="cpp">
<pre name="code" class="cpp">&lt;html&gt;
 &lt;head&gt;
  &lt;script type="application/x-javascript"&gt;
    function draw() {
      var canvas = document.getElementById("canvas");
      if (canvas.getContext) {
        var ctx = canvas.getContext("2d");

        ctx.fillStyle = "rgb(200,0,0)";
        ctx.fillRect (10, 10, 55, 50);

        ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
        ctx.fillRect (30, 30, 55, 50);
      }
    }
  &lt;/script&gt;
 &lt;/head&gt;
 &lt;body onload="draw();"&gt;
   &lt;canvas id="canvas" width="150" height="150"&gt;&lt;/canvas&gt;
 &lt;/body&gt;
&lt;/html&gt;</pre>
</pre>
<div>运行效果如下图所示，分别创建了两个色块，对其进行颜色赋值和透明度设置：</div>
<div><img src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/34.jpg" alt="" width="94" height="84" /></div>
<div>相关代码 <a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/Canvas.zip">下载 </a></div>
<div><strong>•3. </strong><strong>Canvas </strong><strong>动画</strong><strong></strong></div>
<div>Canvas的动画功能是Flash的克星之一，结合了JavaScript和CSS3，可以说任何Flash能够做出的动画在Canvas中都可以实现。Canvas动画的原理和Flash类似：通过移动相应活动的图形来展示动画</div>
<div>如果是一个2D的canvas动画，那么在JavaScript中需要新建以下Object， 本例来源于KineticJS 2d JavaScript Library：</div>
<pre name="code" class="cpp">    this.canvas = document.getElementById(canvasId);
    this.context = this.canvas.getContext("2d");
    this.drawStage = undefined;
    this.listening = false;

    // Canvas Events
    this.mousePos = null;
    this.mouseDown = false;
    this.mouseUp = false;

    // Region Events
    this.currentRegion = null;
    this.regionCounter = 0;
    this.lastRegionIndex = null;

    // Animation
    this.t = 0;
    this.timeInterval = 0;
    this.startTime = 0;
    this.lastTime = 0;
    this.frame = 0;
this.animating = false;</pre>
<div>
<div>其动画部分代码：</div>
<pre name="code" class="cpp">Kinetic_2d.prototype.isAnimating = function(){
    return this.animating;
};

Kinetic_2d.prototype.getFrame = function(){
    return this.frame;
};
Kinetic_2d.prototype.startAnimation = function(){
    this.animating = true;
    var date = new Date();
    this.startTime = date.getTime();
    this.lastTime = this.startTime;

    if (this.drawStage !== undefined) {
        this.drawStage();
    }

    this.animationLoop();
};
Kinetic_2d.prototype.stopAnimation = function(){
    this.animating = false;
};
Kinetic_2d.prototype.getTimeInterval = function(){
    return this.timeInterval;
};
Kinetic_2d.prototype.getTime = function(){
    return this.t;
};
Kinetic_2d.prototype.getFps = function(){
    return this.timeInterval &gt; 0 ? 1000 / this.timeInterval : 0;
};
Kinetic_2d.prototype.animationLoop = function(){
    var that = this;

    this.frame++;
    var date = new Date();
    var thisTime = date.getTime();
    this.timeInterval = thisTime - this.lastTime;
    this.t += this.timeInterval;
    this.lastTime = thisTime;

    if (this.drawStage !== undefined) {
        this.drawStage();
    }

    if (this.animating) {
        requestAnimFrame(function(){
            that.animationLoop();
        });
    }
};</pre>
<div>
<div>读者可以从以下地址下载源码进行测试学习：<a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/Canvas.zip">下载地址</a>。</div>
<div>更多的例子，<br />
<img src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/35.jpg" alt="" width="533" height="285" /></div>
<div>包括Canvas 3D动画，<a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/Canvas.zip">下载地址</a>，Canvas动画是HTML5游戏开发最重要的工具，更多关于Canvas的信息将会和接下来的CSS3一起介绍。</div>
<div>本篇完。</div>
<div>参考资料："Pro. HTML5 Programing" <a href="http://www.kineticjs.com/">http://www.kineticjs.com/</a> ...</div>
<div>相关文章：</div>
<div><a href="http://software.intel.com/zh-cn/blogs/2012/02/20/web-html5-html5/">移动Web应用程序开发 HTML5篇 (一) HTML5简介 </a></div>
<div><a href="http://software.intel.com/zh-cn/blogs/2012/02/22/web-html5/">移动Web应用程序开发 HTML5篇 (二) 新功能介绍和测试</a></div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2012/02/22/webhtml5-canvas-api/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Tizen SDK Intro (2) – 安装</title>
		<link>http://software.intel.com/zh-cn/blogs/2012/02/21/tizen-sdk-intro-2/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2012/02/21/tizen-sdk-intro-2/#comments</comments>
		<pubDate>Tue, 21 Feb 2012 13:17:00 +0000</pubDate>
		<dc:creator>Li Zhang (Intel)</dc:creator>
				<category><![CDATA[移动技术]]></category>
		<category><![CDATA[软件开发工具]]></category>
		<category><![CDATA[SDK]]></category>
		<category><![CDATA[Tizen]]></category>
		<category><![CDATA[泰泽]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2012/02/21/tizen-sdk-intro-2/</guid>
		<description><![CDATA[本文将介绍下Tizen SDK的安装。 1. 软硬件要求  32位Ubuntu10.04/10.10/11.04，目前暂不支持Windows, Mac等系统，未来将会推出（由于Tizen SDK工具链里面需要用到deb相关的，所以Ubuntu是最方便的操作系统，笔者使用的测试环境为Ubuntu 11.10）  至少双核2G的CPU（建议使用有VT支持的CPU）  至少2G内存  至少3G以上剩余硬盘空间（SDK安装后约3.1G，所以少于3G是不行的）  需要有管理员权限（SDK的安装过程中有些配置需要root权限）  分辨率至少1280X1024  使用Sun Java V6或者更高版本（不要使用OpenJDK）  需要安装qemu-kvm, binutils-multiarch, debhelper, fakeroot, realpath, libsdl-gfx1.2-4, gettext, procps, xsltproc, libdbus-1-3, liblua5.1-0, libexif12, libcurl3 以上为官网指明要求的，当然除了java及需要的库之外其他没有达到或者不同也是可以使用的，只不过使用效果可能会差一些，实际笔者在测试时发现使用OpenJDK也是可以正常启动IDE工具的。 2. 下载 根据官网信息，Tizen SDK的安装程序可以在https://developer.tizen.org/download/tizen_sdk.bin处下载。这是一个在线安装程序，所以本身只有不足5M大小。 3. 安装 在安装之前首先要安装好上面提到的库文件及将Ubuntu现在默认安装的OpenJDK替换为sun-java-jdk。  替换java的方式有多种，可以参考使用： add-apt-repository "deb http://archive.canonical.com/ lucid partner" apt-get update apt-get [...]]]></description>
			<content:encoded><![CDATA[<p>本文将介绍下Tizen SDK的安装。<br />
<strong>1. 软硬件要求</strong><br />
 32位Ubuntu10.04/10.10/11.04，目前暂不支持Windows, Mac等系统，未来将会推出（由于Tizen SDK工具链里面需要用到deb相关的，所以Ubuntu是最方便的操作系统，笔者使用的测试环境为Ubuntu 11.10）<br />
 至少双核2G的CPU（建议使用有VT支持的CPU）<br />
 至少2G内存<br />
 至少3G以上剩余硬盘空间（SDK安装后约3.1G，所以少于3G是不行的）<br />
 需要有管理员权限（SDK的安装过程中有些配置需要root权限）<br />
 分辨率至少1280X1024<br />
 使用Sun Java V6或者更高版本（不要使用OpenJDK）<br />
 需要安装qemu-kvm, binutils-multiarch, debhelper, fakeroot, realpath, libsdl-gfx1.2-4, gettext, procps, xsltproc, libdbus-1-3, liblua5.1-0, libexif12, libcurl3<br />
以上为官网指明要求的，当然除了java及需要的库之外其他没有达到或者不同也是可以使用的，只不过使用效果可能会差一些，实际笔者在测试时发现使用OpenJDK也是可以正常启动IDE工具的。</p>
<p><strong>2. 下载</strong><br />
根据官网信息，Tizen SDK的安装程序可以在https://developer.tizen.org/download/tizen_sdk.bin处下载。这是一个在线安装程序，所以本身只有不足5M大小。</p>
<p><strong>3. 安装</strong><br />
在安装之前首先要安装好上面提到的库文件及将Ubuntu现在默认安装的OpenJDK替换为sun-java-jdk。<br />
 <em>替换java</em>的方式有多种，可以参考使用：<br />
add-apt-repository "deb http://archive.canonical.com/ lucid partner"<br />
apt-get update<br />
apt-get install sun-java6-jdk sun-java6-plugin<br />
update-alternatives --config java<br />
update-alternatives --config javac<br />
update-alternatives --config javah<br />
update-alternatives --config java_vm<br />
update-alternatives --config javaws<br />
update-alternatives --config javap<br />
（或者直接使用update-java-alternatives –s java-6-sun）<br />
 <em>安装其他依赖库</em><br />
sudo apt-get install qemu-kvm binutils-multiarch debhelper fakeroot realpath libsdl-gfx1.2-4 gettext procps xsltproc libdbus-1-3 liblua5.1-0 libexif12 libcurl3<br />
 <em>运行安装程序安装</em><br />
Chmod +x tizen_sdk.bin<br />
./tizen_sdk.bin<br />
（如果需要使用代理，可以在其后加入参数，格式为 ./tizen_sdk.bin –proxy :）</p>
<div id="attachment_400009764" class="wp-caption alignnone" style="width: 310px"><a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/tizen-1.jpg"><img class="size-medium wp-image-400009764" src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/tizen-1-300x227.jpg" alt="Install new version of Tizen SDK" width="300" height="227" /></a><p class="wp-caption-text">SDK安装示意图一</p></div>
<div id="attachment_400009769" class="wp-caption alignnone" style="width: 310px"><a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/tizen-2-1.jpg"><img class="size-medium wp-image-400009769" src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/tizen-2-1-300x228.jpg" alt="Installation step - choose components" width="300" height="228" /></a><p class="wp-caption-text">SDK安装示意图二</p></div>
<div id="attachment_400009770" class="wp-caption alignnone" style="width: 310px"><a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/tizen-2-2.jpg"><img class="size-medium wp-image-400009770" src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/tizen-2-2-300x227.jpg" alt="Installation step - downloading" width="300" height="227" /></a><p class="wp-caption-text">SDK安装示意图三</p></div>
<p>整个安装过程还是比较简单和傻瓜似的，前面会下载比较长时间（取决于网速），安装期间会有几次弹出框要求输入系统的root密码，所以不是运行一夜之后就能安装好的*_*。</p>
<div id="attachment_400009768" class="wp-caption alignnone" style="width: 310px"><a href="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/tizen-3.jpg"><img class="size-medium wp-image-400009768" src="http://software.intel.com/zh-cn/blogs/wordpress/wp-content/uploads/2012/02/tizen-3-300x228.jpg" alt="Install Finished!" width="300" height="228" /></a><p class="wp-caption-text">成功安装示意图</p></div>
<p>看到这个页面时，恭喜你，Tizen SDK已经安装完毕，下面我们就可以使用它自带的工具来尝试了。</p>
<p>References:</p>
<p>https://developer.tizen.org/sdk_install.html</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2012/02/21/tizen-sdk-intro-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>如何用 VC++ 编写 MIDI 文件播放程序</title>
		<link>http://software.intel.com/zh-cn/blogs/2012/02/14/vc-midi/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2012/02/14/vc-midi/#comments</comments>
		<pubDate>Tue, 14 Feb 2012 09:35:46 +0000</pubDate>
		<dc:creator>playboy1</dc:creator>
				<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[图形和视觉计算]]></category>
		<category><![CDATA[软件开发工具]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2012/02/14/vc-midi/</guid>
		<description><![CDATA[  MIDI的意思是乐器数字接口：（Musical Instrument Digital Interface）它是早在微软开发Windows以前就有的一个用于电子键盘的标准。MIDI定义了一个传输和存储音乐信息的协议。 Win32 API 提供了几种处理MIDI数据的方法。在Windows中有很多方法播放MIDI文件。这里我们讨论一种最简单的方法。 01.ShellExecute (hWnd, "open", "c:\\windows\\media\\Canyon.mid", NULL, NULL, SW_SHOWNORMAL); ShellExecute和ShellExecuteEx是两个功能强大的函数，毫不夸张地讲，他们能打开Windows中的任何文件。但是有一个缺点，当我们用他打开MIDI文件时，它启动的是多媒体播放器，却不能自动播放，还得用户手工点击“play”键。这一点在许多场合不实用。解决此问题的方法是使用Windows的MCI类来处理MIDI文件，就象下面这样： 01.HWND hMCIWnd; 02.hMCIWnd = MCIWndCreate(NULL, hInst, 0, "c:\\windows\\media\\Canyon.mid"); 03.MCIWndPlay(hMCIWnd); MCI类能处理所有类型的多媒体格式，使用MCI类还能在控件窗口或者自己的应用窗口中选择播放选项以及其它的类型的选项。注意：使用MCI类时必须包含vfw.h文件，并且将vfw32.lib加到输入库列表中。]]></description>
			<content:encoded><![CDATA[<p> </p>
<p>MIDI的意思是乐器数字接口：（Musical Instrument Digital Interface）它是早在微软开发Windows以前就有的一个用于电子键盘的标准。MIDI定义了一个传输和存储音乐信息的协议。</p>
<p>Win32 API 提供了几种处理MIDI数据的方法。在Windows中有很多方法播放MIDI文件。这里我们讨论一种最简单的方法。<br />
01.ShellExecute (hWnd, "open", "c:\\windows\\media\\Canyon.mid", NULL, NULL, SW_SHOWNORMAL);<br />
ShellExecute和ShellExecuteEx是两个功能强大的函数，毫不夸张地讲，他们能打开Windows中的任何文件。但是有一个缺点，当我们用他打开MIDI文件时，它启动的是多媒体播放器，却不能自动播放，还得用户手工点击“play”键。这一点在许多场合不实用。解决此问题的方法是使用Windows的MCI类来处理MIDI文件，就象下面这样：<br />
01.HWND hMCIWnd; 02.hMCIWnd = MCIWndCreate(NULL, hInst, 0, "c:\\windows\\media\\Canyon.mid"); 03.MCIWndPlay(hMCIWnd);<br />
MCI类能处理所有类型的多媒体格式，使用MCI类还能在控件窗口或者自己的应用窗口中选择播放选项以及其它的类型的选项。注意：使用MCI类时必须包含vfw.h文件，并且将vfw32.lib加到输入库列表中。</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2012/02/14/vc-midi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在 Win32 下用 C++ 实现多线程读写锁</title>
		<link>http://software.intel.com/zh-cn/blogs/2012/02/14/win32-c/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2012/02/14/win32-c/#comments</comments>
		<pubDate>Tue, 14 Feb 2012 09:34:54 +0000</pubDate>
		<dc:creator>chexlong</dc:creator>
				<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[并行计算]]></category>
		<category><![CDATA[软件开发工具]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2012/02/14/win32-c/</guid>
		<description><![CDATA[  读写锁实际是一种特殊的自旋锁，它把对共享资源的访问者划分成读者和写者，读者只对共享资源进行读访问，写者则需要对共享资源进行写操作。这种锁相对于自旋锁而言，能提高并发性，因为在多处理器系统中，它允许同时有多个读者来访问共享资源，最大可能的读者数为实际的逻辑CPU数。写者是排他性的，一个读写锁同时只能有一个写者或多个读者（与CPU数相关），但不能同时既有读者又有写者。 现在Win32的API，用C++实现自己的读写锁。这组API包括：CreateMutex，CreateEvent，WaitForSingleObject，WaitForMultipleObjects，ResetEvent，ReleaseMutex，SetEvent，CloseHandle。以下代码在VS2005下，已经编译通过。 RWLockImpl.h 01.#ifndef _RWLockImpl_Header 02.#define _RWLockImpl_Header 03. 04.#include 05.#include 06.#include 07.#include 08. 09.using namespace std; 10. 11./* 12. 读写锁允许当前的多个读用户访问保护资源，但只允许一个写读者访问保护资源 13.*/ 14. 15.//----------------------------------------------------------------- 16.class CRWLockImpl 17.{ 18.protected: 19. CRWLockImpl(); 20. ~CRWLockImpl(); 21. void ReadLockImpl(); 22. bool TryReadLockImpl(); 23. void WriteLockImpl(); 24. bool TryWriteLockImpl(); 25. void UnlockImpl(); 26. 27.private: 28. void AddWriter(); 29. void RemoveWriter(); [...]]]></description>
			<content:encoded><![CDATA[<p> </p>
<p>读写锁实际是一种特殊的自旋锁，它把对共享资源的访问者划分成读者和写者，读者只对共享资源进行读访问，写者则需要对共享资源进行写操作。这种锁相对于自旋锁而言，能提高并发性，因为在多处理器系统中，它允许同时有多个读者来访问共享资源，最大可能的读者数为实际的逻辑CPU数。写者是排他性的，一个读写锁同时只能有一个写者或多个读者（与CPU数相关），但不能同时既有读者又有写者。</p>
<p>现在Win32的API，用C++实现自己的读写锁。这组API包括：CreateMutex，CreateEvent，WaitForSingleObject，WaitForMultipleObjects，ResetEvent，ReleaseMutex，SetEvent，CloseHandle。以下代码在VS2005下，已经编译通过。</p>
<p>RWLockImpl.h</p>
<p>01.<span style="font-size: 16px;">#ifndef _RWLockImpl_Header<br />
02.#define _RWLockImpl_Header<br />
03.<br />
04.#include<br />
05.#include<br />
06.#include<br />
07.#include<br />
08.<br />
09.using namespace std;<br />
10.<br />
11./*<br />
12. 读写锁允许当前的多个读用户访问保护资源，但只允许一个写读者访问保护资源<br />
13.*/<br />
14.<br />
15.//-----------------------------------------------------------------<br />
16.class CRWLockImpl<br />
17.{<br />
18.protected:<br />
19. CRWLockImpl();<br />
20. ~CRWLockImpl();<br />
21. void ReadLockImpl();<br />
22. bool TryReadLockImpl();<br />
23. void WriteLockImpl();<br />
24. bool TryWriteLockImpl();<br />
25. void UnlockImpl();<br />
26.<br />
27.private:<br />
28. void AddWriter();<br />
29. void RemoveWriter();<br />
30. DWORD TryReadLockOnce();<br />
31.<br />
32. HANDLE m_mutex;<br />
33. HANDLE m_readEvent;<br />
34. HANDLE m_writeEvent;<br />
35. unsigned m_readers;<br />
36. unsigned m_writersWaiting;<br />
37. unsigned m_writers;<br />
38.};<br />
39.<br />
40.//-----------------------------------------------------------------<br />
41.<br />
42.class CMyRWLock: private CRWLockImpl<br />
43.{<br />
44.public:<br />
45.<br />
46. //创建读/写锁<br />
47. CMyRWLock(){};<br />
48.<br />
49. //销毁读/写锁<br />
50. ~CMyRWLock(){};<br />
51.<br />
52. //获取读锁<br />
53. //如果其它一个线程占有写锁，则当前线程必须等待写锁被释放，才能对保护资源进行访问<br />
54. void ReadLock();<br />
55.<br />
56. //尝试获取一个读锁<br />
57. //如果获取成功，则立即返回true，否则当另一个线程占有写锁，则返回false<br />
58. bool TryReadLock();<br />
59.<br />
60. //获取写锁<br />
61. //如果一个或更多线程占有读锁，则必须等待所有锁被释放<br />
62. //如果相同的一个线程已经占有一个读锁或写锁，则返回结果不确定<br />
63. void WriteLock();<br />
64.<br />
65. //尝试获取一个写锁<br />
66. //如果获取成功，则立即返回true，否则当一个或更多其它线程占有读锁，返回false<br />
67. //如果相同的一个线程已经占有一个读锁或写锁，则返回结果不确定<br />
68. bool TryWriteLock();<br />
69.<br />
70. //释放一个读锁或写锁<br />
71. void Unlock();<br />
72.<br />
73.private:<br />
74. CMyRWLock(const CMyRWLock&amp;);<br />
75. CMyRWLock&amp; operator = (const CMyRWLock&amp;);<br />
76.};<br />
77.<br />
78.inline void CMyRWLock::ReadLock()<br />
79.{<br />
80. ReadLockImpl();<br />
81.}<br />
82.<br />
83.inline bool CMyRWLock::TryReadLock()<br />
84.{<br />
85. return TryReadLockImpl();<br />
86.}<br />
87.<br />
88.inline void CMyRWLock::WriteLock()<br />
89.{<br />
90. WriteLockImpl();<br />
91.}<br />
92.<br />
93.inline bool CMyRWLock::TryWriteLock()<br />
94.{<br />
95. return TryWriteLockImpl();<br />
96.}<br />
97.<br />
98.inline void CMyRWLock::Unlock()<br />
99.{<br />
100. UnlockImpl();<br />
101.}<br />
102.<br />
103.<br />
104.#endif</span><br />
RWLockImpl.cpp<br />
01.<span style="font-size: 16px;">#include "RWLockImpl.h"<br />
02.<br />
03.CRWLockImpl::CRWLockImpl(): m_readers(0), m_writersWaiting(0), m_writers(0)<br />
04.{<br />
05. m_mutex = CreateMutex(NULL, FALSE, NULL);<br />
06. if (m_mutex == NULL)<br />
07. cout&lt;&lt;"cannot create reader/writer lock"&lt;&lt;endl;<br />
08.<br />
09. m_readEvent = CreateEvent(NULL, TRUE, TRUE, NULL);<br />
10. if (m_readEvent == NULL)<br />
11. cout&lt;&lt;"cannot create reader/writer lock"&lt;&lt;endl;<br />
12.<br />
13. m_writeEvent = CreateEvent(NULL, TRUE, TRUE, NULL);<br />
14. if (m_writeEvent == NULL)<br />
15. cout&lt;&lt;"cannot create reader/writer lock"&lt;&lt;endl;<br />
16.}<br />
17.<br />
18.CRWLockImpl::~CRWLockImpl()<br />
19.{<br />
20. CloseHandle(m_mutex);<br />
21. CloseHandle(m_readEvent);<br />
22. CloseHandle(m_writeEvent);<br />
23.}<br />
24.<br />
25.inline void CRWLockImpl::AddWriter()<br />
26.{<br />
27. switch (WaitForSingleObject(m_mutex, INFINITE))<br />
28. {<br />
29. case WAIT_OBJECT_0:<br />
30. if (++m_writersWaiting == 1)<br />
31. ResetEvent(m_readEvent);<br />
32. ReleaseMutex(m_mutex);<br />
33. break;<br />
34. default:<br />
35. cout&lt;&lt;"cannot lock reader/writer lock"&lt;&lt;endl;<br />
36. }<br />
37.}<br />
38.<br />
39.inline void CRWLockImpl::RemoveWriter()<br />
40.{<br />
41. switch (WaitForSingleObject(m_mutex, INFINITE))<br />
42. {<br />
43. case WAIT_OBJECT_0:<br />
44. if (--m_writersWaiting == 0 &amp;&amp; m_writers == 0)<br />
45. SetEvent(m_readEvent);<br />
46. ReleaseMutex(m_mutex);<br />
47. break;<br />
48. default:<br />
49. cout&lt;&lt;"cannot lock reader/writer lock"&lt;&lt;endl;<br />
50. }<br />
51.}<br />
52.<br />
53.void CRWLockImpl::ReadLockImpl()<br />
54.{<br />
55. HANDLE h[2];<br />
56. h[0] = m_mutex;<br />
57. h[1] = m_readEvent;<br />
58. switch (WaitForMultipleObjects(2, h, TRUE, INFINITE))<br />
59. {<br />
60. case WAIT_OBJECT_0:<br />
61. case WAIT_OBJECT_0 + 1:<br />
62. ++m_readers;<br />
63. ResetEvent(m_writeEvent);<br />
64. ReleaseMutex(m_mutex);<br />
65. assert(m_writers == 0);<br />
66. break;<br />
67. default:<br />
68. cout&lt;&lt;"cannot lock reader/writer lock"&lt;&lt;endl;<br />
69. }<br />
70.}<br />
71.<br />
72.bool CRWLockImpl::TryReadLockImpl()<br />
73.{<br />
74. for (;;)<br />
75. {<br />
76. if (m_writers != 0 || m_writersWaiting != 0)<br />
77. return false;<br />
78.<br />
79. DWORD result = TryReadLockOnce();<br />
80. switch (result)<br />
81. {<br />
82. case WAIT_OBJECT_0:<br />
83. case WAIT_OBJECT_0 + 1:<br />
84. return true;<br />
85. case WAIT_TIMEOUT:<br />
86. continue;<br />
87. default:<br />
88. cout&lt;&lt;"cannot lock reader/writer lock"&lt;&lt;endl;<br />
89. }<br />
90. }<br />
91.}<br />
92.<br />
93.void CRWLockImpl::WriteLockImpl()<br />
94.{<br />
95. AddWriter();<br />
96. HANDLE h[2];<br />
97. h[0] = m_mutex;<br />
98. h[1] = m_writeEvent;<br />
99. switch (WaitForMultipleObjects(2, h, TRUE, INFINITE))<br />
100. {<br />
101. case WAIT_OBJECT_0:<br />
102. case WAIT_OBJECT_0 + 1:<br />
103. --m_writersWaiting;<br />
104. ++m_readers;<br />
105. ++m_writers;<br />
106. ResetEvent(m_readEvent);<br />
107. ResetEvent(m_writeEvent);<br />
108. ReleaseMutex(m_mutex);<br />
109. assert(m_writers == 1);<br />
110. break;<br />
111. default:<br />
112. RemoveWriter();<br />
113. cout&lt;&lt;"cannot lock reader/writer lock"&lt;&lt;endl;<br />
114. }<br />
115.}<br />
116.<br />
117.bool CRWLockImpl::TryWriteLockImpl()<br />
118.{<br />
119. AddWriter();<br />
120. HANDLE h[2];<br />
121. h[0] = m_mutex;<br />
122. h[1] = m_writeEvent;<br />
123. switch (WaitForMultipleObjects(2, h, TRUE, 1))<br />
124. {<br />
125. case WAIT_OBJECT_0:<br />
126. case WAIT_OBJECT_0 + 1:<br />
127. --m_writersWaiting;<br />
128. ++m_readers;<br />
129. ++m_writers;<br />
130. ResetEvent(m_readEvent);<br />
131. ResetEvent(m_writeEvent);<br />
132. ReleaseMutex(m_mutex);<br />
133. assert(m_writers == 1);<br />
134. return true;<br />
135. case WAIT_TIMEOUT:<br />
136. RemoveWriter();<br />
137. default:<br />
138. RemoveWriter();<br />
139. cout&lt;&lt;"cannot lock reader/writer lock"&lt;&lt;endl;<br />
140. }<br />
141. return false;<br />
142.}<br />
143.<br />
144.void CRWLockImpl::UnlockImpl()<br />
145.{<br />
146. switch (WaitForSingleObject(m_mutex, INFINITE))<br />
147. {<br />
148. case WAIT_OBJECT_0:<br />
149. m_writers = 0;<br />
150. if (m_writersWaiting == 0) SetEvent(m_readEvent);<br />
151. if (--m_readers == 0) SetEvent(m_writeEvent);<br />
152. ReleaseMutex(m_mutex);<br />
153. break;<br />
154. default:<br />
155. cout&lt;&lt;"cannot unlock reader/writer lock"&lt;&lt;endl;<br />
156. }<br />
157.}<br />
158.<br />
159.DWORD CRWLockImpl::TryReadLockOnce()<br />
160.{<br />
161. HANDLE h[2];<br />
162. h[0] = m_mutex;<br />
163. h[1] = m_readEvent;<br />
164. DWORD result = WaitForMultipleObjects(2, h, TRUE, 1);<br />
165. switch (result)<br />
166. {<br />
167. case WAIT_OBJECT_0:<br />
168. case WAIT_OBJECT_0 + 1:<br />
169. ++m_readers;<br />
170. ResetEvent(m_writeEvent);<br />
171. ReleaseMutex(m_mutex);<br />
172. assert(m_writers == 0);<br />
173. return result;<br />
174. case WAIT_TIMEOUT:<br />
175. default:<br />
176. cout&lt;&lt;"cannot lock reader/writer lock"&lt;&lt;endl;<br />
177. }<br />
178. return result;<br />
179.}<br />
180.</span><br />
下边是测试代码<br />
01.<span style="font-size: 16px;">// MyRWLockWin32.cpp : 定义控制台应用程序的入口点。<br />
02.//<br />
03.<br />
04.#include "RWLockImpl.h"<br />
05.<br />
06.//创建一个读写锁对象<br />
07.CMyRWLock g_myRWLock;<br />
08.volatile int g_counter = 0;<br />
09.<br />
10.//线程函数<br />
11.unsigned int __stdcall StartThread(void *pParam)<br />
12.{<br />
13. int lastCount = 0;<br />
14. for (int i = 0; i &lt; 10000; ++i)<br />
15. {<br />
16. g_myRWLock.ReadLock();<br />
17. lastCount = g_counter;<br />
18. //在读锁域，两个线程不断循环交替访问全局变量g_counter<br />
19. for (int k = 0; k &lt; 100; ++k)<br />
20. {<br />
21. if (g_counter != lastCount)<br />
22. cout&lt;&lt;"the value of g_counter has been updated."&lt;&lt;endl;<br />
23. Sleep(0);<br />
24. }<br />
25. g_myRWLock.Unlock();<br />
26.<br />
27.<br />
28. g_myRWLock.WriteLock();<br />
29. //在写锁域，只有一个线程可以修改全局变量g_counter的值<br />
30. for (int k = 0; k &lt; 100; ++k)<br />
31. {<br />
32. --g_counter;<br />
33. Sleep(0);<br />
34. }<br />
35. for (int k = 0; k &lt; 100; ++k)<br />
36. {<br />
37. ++g_counter;<br />
38. Sleep(0);<br />
39. }<br />
40. ++g_counter;<br />
41. if (g_counter &lt;= lastCount)<br />
42. cout&lt;&lt;"the value of g_counter is error."&lt;&lt;endl;<br />
43. g_myRWLock.Unlock();<br />
44. }<br />
45.<br />
46. return (unsigned int)0;<br />
47.}<br />
48.<br />
49.int main(int argc, char* argv[])<br />
50.{<br />
51. HANDLE hThread1, hThread2;<br />
52. unsigned int uiThreadId1, uiThreadId2;<br />
53.<br />
54. //创建两个工作线程<br />
55. hThread1 = (HANDLE)_beginthreadex(NULL, 0, &amp;StartThread, (void *)NULL, 0, &amp;uiThreadId1);<br />
56. hThread2 = (HANDLE)_beginthreadex(NULL, 0, &amp;StartThread, (void *)NULL, 0, &amp;uiThreadId2);<br />
57.<br />
58. //等待线程结束<br />
59. DWORD dwRet = WaitForSingleObject(hThread1,INFINITE);<br />
60. if ( dwRet == WAIT_TIMEOUT )<br />
61. {<br />
62. TerminateThread(hThread1,0);<br />
63. }<br />
64. dwRet = WaitForSingleObject(hThread2,INFINITE);<br />
65. if ( dwRet == WAIT_TIMEOUT )<br />
66. {<br />
67. TerminateThread(hThread2,0);<br />
68. }<br />
69.<br />
70. //关闭线程句柄，释放资源<br />
71. CloseHandle(hThread1);<br />
72. CloseHandle(hThread2);<br />
73.<br />
74. assert (g_counter == 20000);<br />
75.<br />
76. system("pause");<br />
77. return 0;<br />
78.}</span></p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2012/02/14/win32-c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

