<?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; zenny_chen_</title>
	<atom:link href="http://software.intel.com/zh-cn/blogs/author/zenny_chen_/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>对多核共享变量的读写操作</title>
		<link>http://software.intel.com/zh-cn/blogs/2010/08/18/400005150/</link>
		<comments>http://software.intel.com/zh-cn/blogs/2010/08/18/400005150/#comments</comments>
		<pubDate>Wed, 18 Aug 2010 06:34:51 +0000</pubDate>
		<dc:creator>zenny_chen_</dc:creator>
				<category><![CDATA[博客征文专栏]]></category>
		<category><![CDATA[并行计算]]></category>

		<guid isPermaLink="false">http://software.intel.com/zh-cn/blogs/2010/08/18/400005150/</guid>
		<description><![CDATA[在PC处理器中，往往没有像嵌入式系统那样含有一块多核共享的高速缓存（一般是SRAM）。也就是说我们在PC处理器的多核共享变量都是统一被映射到内存（DDR）中去的。那么这就会导致一系列的问题。 首先，由于每个核都有自己的独立的L1 Cache（包括数据和指令），而多个核共享一个L2 Cache，以及更高层级的Cache。 那么在某一个核中对一个多核共享变量做读写操作的话，若采用一般指令进行写，那么这变量的值仅仅会在那个核的L1 Cache中折腾，而可能不会影响到存储器中的那个真正的对象。 然后，这也会导致在某一个核中，你每次对该共享变量进行读操作时，其值可能不是最新的，即，在你刚读好这个变量时它可能已经被其它核给修改了。 因此，这得出一个结论：你不能用普通的写操作来修改多核共享变量；在你读多核共享变量前必须确保其它核没有再次修改它。 我们对多核共享变量进行修改时，会采取具有锁总线特性的指令。在x86中有：xchg、cmpxchg等，除此以外还有带有LOCK前缀的基本算术运算操作。在Blackfin561 Dual-Core DSP中，可以使用testset指令；ARMv7以前的处理器可以用SWP和SWPB，在ARMv7架构中加入了更强大的LDREX和STREX对，形成LL-SC作为原子操作指令对。 因此，如果我们将多核共享变量作为同步锁的话，那么用SWAP、TEST AND SET等指令对其进行读、写同时操作，并且加锁总线。如果我们在操作一个多核共享的数据结构，那么我们在操作前应该上锁，然后每次对必要结果的修改应该用上述带有锁总线的指令进行操作。还有一种是用普通的写指令将结果写到Cache后，然后再无效化当前核的整个Cache。但是这个做法也很耗时间，而且原本已经进Cache的数据也都被清空了。 当然，在很多时候，我们为了图个方便，会把相同的数据结构赋值多份给每个核，呵呵。虽然这样会比较浪费空间，但也是一种手段。 下面给各位看一下加锁总线和没有锁总线的执行区别： view plaincopy to clipboardprint? #include #define INTRIN_RDTSC(tick) __asm__("rdtsc" : "=A"(tick)) int main(void) { register int a = 100; int m = 10; unsigned long long beginTicks, endTicks; // register type swap INTRIN_RDTSC(beginTicks); for(int i=0; i&#60;10000; i++) __asm__ volatile("xchg %0, [...]]]></description>
			<content:encoded><![CDATA[<p>在PC处理器中，往往没有像嵌入式系统那样含有一块多核共享的高速缓存（一般是SRAM）。也就是说我们在PC处理器的多核共享变量都是统一被映射到内存（DDR）中去的。那么这就会导致一系列的问题。</p>
<p>首先，由于每个核都有自己的独立的L1 Cache（包括数据和指令），而多个核共享一个L2 Cache，以及更高层级的Cache。 那么在某一个核中对一个多核共享变量做读写操作的话，若采用一般指令进行写，那么这变量的值仅仅会在那个核的L1 Cache中折腾，而可能不会影响到存储器中的那个真正的对象。</p>
<p>然后，这也会导致在某一个核中，你每次对该共享变量进行读操作时，其值可能不是最新的，即，在你刚读好这个变量时它可能已经被其它核给修改了。</p>
<p>因此，这得出一个结论：你不能用普通的写操作来修改多核共享变量；在你读多核共享变量前必须确保其它核没有再次修改它。</p>
<p>我们对多核共享变量进行修改时，会采取具有锁总线特性的指令。在x86中有：xchg、cmpxchg等，除此以外还有带有LOCK前缀的基本算术运算操作。在Blackfin561 Dual-Core DSP中，可以使用testset指令；ARMv7以前的处理器可以用SWP和SWPB，在ARMv7架构中加入了更强大的LDREX和STREX对，形成LL-SC作为原子操作指令对。</p>
<p>因此，如果我们将多核共享变量作为同步锁的话，那么用SWAP、TEST AND SET等指令对其进行读、写同时操作，并且加锁总线。如果我们在操作一个多核共享的数据结构，那么我们在操作前应该上锁，然后每次对必要结果的修改应该用上述带有锁总线的指令进行操作。还有一种是用普通的写指令将结果写到Cache后，然后再无效化当前核的整个Cache。但是这个做法也很耗时间，而且原本已经进Cache的数据也都被清空了。</p>
<p>当然，在很多时候，我们为了图个方便，会把相同的数据结构赋值多份给每个核，呵呵。虽然这样会比较浪费空间，但也是一种手段。</p>
<p>下面给各位看一下加锁总线和没有锁总线的执行区别：</p>
<p>view plaincopy to clipboardprint?<br />
#include</p>
<p>#define INTRIN_RDTSC(tick) __asm__("rdtsc" : "=A"(tick))</p>
<p>int main(void)<br />
{<br />
register int a = 100;<br />
int m = 10;<br />
unsigned long long beginTicks, endTicks;<br />
// register type swap<br />
INTRIN_RDTSC(beginTicks);</p>
<p>for(int i=0; i&lt;10000; i++)<br />
__asm__ volatile("xchg %0, %1" : : "r"(a), "r"(m));</p>
<p>INTRIN_RDTSC(endTicks);</p>
<p>printf("The register type swap is: %llu\r\n", endTicks - beginTicks);</p>
<p>// memory type swap<br />
INTRIN_RDTSC(beginTicks);</p>
<p>for(int i=0; i&lt;10000; i++)<br />
__asm__ volatile("xchg %0, (%1)" : : "r"(a), "r"(&amp;m));</p>
<p>INTRIN_RDTSC(endTicks);</p>
<p>printf("The memory type swap is: %llu\r\n", endTicks - beginTicks);</p>
<p>// normal add<br />
INTRIN_RDTSC(beginTicks);</p>
<p>for(int i=0; i&lt;10000; i++)<br />
__asm__ volatile("add %0, (%1)" : : "r"(a), "r"(&amp;m));</p>
<p>INTRIN_RDTSC(endTicks);</p>
<p>printf("The normal add swap is: %llu\r\n", endTicks - beginTicks);</p>
<p>// lock add<br />
INTRIN_RDTSC(beginTicks);</p>
<p>for(int i=0; i&lt;10000; i++)<br />
__asm__ volatile("lock add %0, (%1)" : : "r"(a), "r"(&amp;m));</p>
<p>INTRIN_RDTSC(endTicks);</p>
<p>printf("The lock add is: %llu\r\n", endTicks - beginTicks);<br />
}<br />
#include</p>
<p>#define INTRIN_RDTSC(tick) __asm__("rdtsc" : "=A"(tick))</p>
<p>int main(void)<br />
{<br />
register int a = 100;<br />
int m = 10;<br />
unsigned long long beginTicks, endTicks;<br />
// register type swap<br />
INTRIN_RDTSC(beginTicks);</p>
<p>for(int i=0; i&lt;10000; i++)<br />
__asm__ volatile("xchg %0, %1" : : "r"(a), "r"(m));</p>
<p>INTRIN_RDTSC(endTicks);</p>
<p>printf("The register type swap is: %llu\r\n", endTicks - beginTicks);</p>
<p>// memory type swap<br />
INTRIN_RDTSC(beginTicks);</p>
<p>for(int i=0; i&lt;10000; i++)<br />
__asm__ volatile("xchg %0, (%1)" : : "r"(a), "r"(&amp;m));</p>
<p>INTRIN_RDTSC(endTicks);</p>
<p>printf("The memory type swap is: %llu\r\n", endTicks - beginTicks);</p>
<p>// normal add<br />
INTRIN_RDTSC(beginTicks);</p>
<p>for(int i=0; i&lt;10000; i++)<br />
__asm__ volatile("add %0, (%1)" : : "r"(a), "r"(&amp;m));</p>
<p>INTRIN_RDTSC(endTicks);</p>
<p>printf("The normal add swap is: %llu\r\n", endTicks - beginTicks);</p>
<p>// lock add<br />
INTRIN_RDTSC(beginTicks);</p>
<p>for(int i=0; i&lt;10000; i++)<br />
__asm__ volatile("lock add %0, (%1)" : : "r"(a), "r"(&amp;m));</p>
<p>INTRIN_RDTSC(endTicks);</p>
<p>printf("The lock add is: %llu\r\n", endTicks - beginTicks);<br />
}</p>
<p>上述代码，使用LLVM1.5，GNU99编译选项编译</p>
]]></content:encoded>
			<wfw:commentRss>http://software.intel.com/zh-cn/blogs/2010/08/18/400005150/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

