File: Fenced_Data_Transfer.htm

package info (click to toggle)
tbb 4.2~20140122-5
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 21,492 kB
  • ctags: 21,278
  • sloc: cpp: 92,813; ansic: 9,775; asm: 1,070; makefile: 1,057; sh: 351; java: 226; objc: 98; pascal: 71; xml: 41
file content (218 lines) | stat: -rwxr-xr-x 7,980 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
<!DOCTYPE html
  PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<!-- saved from url=(0014)about:internet -->
<html xmlns:MSHelp="http://www.microsoft.com/MSHelp/" lang="en-us" xml:lang="en-us"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<meta name="DC.Type" content="topic">
<meta name="DC.Title" content="Fenced Data Transfer">
<meta name="DC.subject" content="Fenced Data Transfer">
<meta name="keywords" content="Fenced Data Transfer">
<meta name="DC.Relation" scheme="URI" content="../../tbb_userguide/Design_Patterns/Design_Patterns.htm">
<meta name="DC.Relation" scheme="URI" content="Lazy_Initialization.htm#Lazy_Initialization">
<meta name="DC.Format" content="XHTML">
<meta name="DC.Identifier" content="Fenced_Data_Transfer">
<link rel="stylesheet" type="text/css" href="../../intel_css_styles.css">
<title>Fenced Data Transfer</title>
<xml>
<MSHelp:Attr Name="DocSet" Value="Intel"></MSHelp:Attr>
<MSHelp:Attr Name="Locale" Value="kbEnglish"></MSHelp:Attr>
<MSHelp:Attr Name="TopicType" Value="kbReference"></MSHelp:Attr>
</xml>
</head>
<body id="Fenced_Data_Transfer">
 <!-- ==============(Start:NavScript)================= -->
 <script src="..\..\NavScript.js" language="JavaScript1.2" type="text/javascript"></script>
 <script language="JavaScript1.2" type="text/javascript">WriteNavLink(2);</script>
 <!-- ==============(End:NavScript)================= -->
<a name="Fenced_Data_Transfer"><!-- --></a>

 
  <h1 class="topictitle1">Fenced Data Transfer</h1>
 
   
  <div> 
	 <div class="section"><h2 class="sectiontitle">Problem</h2> 
		 
		<p>Write a message to memory and have another processor read it on
		  hardware that does not have a sequentially consistent memory model. 
		</p>
 
	 </div>
 
	 <div class="section"><h2 class="sectiontitle">Context</h2> 
		 
		<p>The problem normally arises only when unsynchronized threads
		  concurrently act on a memory location, or are using reads and writes to create
		  synchronization. High level synchronization constructs normally include
		  mechanisms that prevent unwanted reordering. 
		</p>
 
		<p>Modern hardware and compilers can reorder memory operations in a way
		  that preserves the order of a thread's operation from its viewpoint, but not as
		  observed by other threads. A serial common idiom is to write a message and mark
		  it as ready to ready as shown in the following code: 
		</p>
 
		<pre>bool Ready;                    
std::string Message;
&nbsp;
void Send( const std::string&amp; src ) {. // Executed by thread 1
   Message=src;
   Ready = true;
}
&nbsp;
bool Receive( std::string&amp; dst ) {    // Executed by thread 2
   bool result = Ready;
   if( result ) dst=Message;
   return result;              // Return true if message was received.
}</pre> 
		<p>Two key assumptions of the code are: 
		</p>
 
		<ol class="abc"> 
		  <li> 
			 <p><samp class="codeph">Ready</samp> does not become true until 
				<samp class="codeph">Message</samp> is written. 
			 </p>
 
		  </li>
 
		  <li> 
			 <p><samp class="codeph">Message</samp> is not read until 
				<samp class="codeph">Ready</samp> becomes true. 
			 </p>
 
		  </li>
 
		</ol>
 
		<p>These assumptions are trivially true on uniprocessor hardware.
		  However, they may break on multiprocessor hardware. Reordering by the hardware
		  or compiler can cause the sender's writes to appear out of order to the
		  receiver (thus breaking condition a) or the receiver's reads to appear out of
		  order (thus breaking condition b). 
		</p>
 
	 </div>
 
	 <div class="section"><h2 class="sectiontitle">Forces</h2> 
		 
		<ul type="disc"> 
		  <li> 
			 <p>Creating synchronization via raw reads and writes. 
			 </p>
 
		  </li>
 
		</ul>
 
	 </div>
 
	 <div class="section"><h2 class="sectiontitle">Related</h2> 
		 
		<ul type="disc"> 
		  <li>Lazy Initialization 
		  </li>
 
		</ul>
 
	 </div>
 
	 <div class="section"><h2 class="sectiontitle">Solution</h2> 
		 
		<p>Change the flag from 
		  <samp class="codeph">bool</samp> to 
		  <samp class="codeph">tbb::atomic&lt;bool&gt;</samp> for the flag that indicates
		  when the message is ready. Here is the previous example, with modifications
		  shown in 
		  <samp class="codeph"><span style="color:blue"><strong>bold font</strong></span></samp>. 
		</p>
 
		<pre><span style="color:blue"><strong>tbb::atomic&lt;</strong></span>bool<span style="color:blue"><strong>&gt;</strong></span> Ready;
std::string Message;
&nbsp;
void Send( const std::string&amp; src ) {. // Executed by thread 1
   Message=src;
   Ready = true;
}
&nbsp;
bool Receive( std::string&amp; dst ) {    // Executed by thread 2
   bool result = Ready;
   if( result ) dst=Message;
   return result;              // Return true if message was received.
}</pre> 
		<p>A write to a 
		  <samp class="codeph">tbb::atomic</samp> value has 
		  <em>release</em> semantics, which means that all of its prior writes will
		  be seen before the releasing write. A read from 
		  <samp class="codeph">tbb::atomic</samp> value has 
		  <em>acquire</em> semantics, which means that all of its subsequent reads
		  will happen after the acquiring read. The implementation of 
		  <samp class="codeph">tbb::atomic</samp> ensures that both the compiler and the
		  hardware observe these ordering constraints. 
		</p>
 
	 </div>
 
	 <div class="section"><h2 class="sectiontitle">Variations</h2> 
		 
		<p>Higher level synchronization constructs normally include the necessary
		  
		  <em>acquire</em> and 
		  <em>release</em> fences. For example, mutexes are normally implemented
		  such that acquisition of a lock has 
		  <em>acquire</em> semantics and release of a lock has 
		  <em>release</em> semantics. Thus a thread that acquires a lock on a mutex
		  always sees any memory writes done by another thread before it released a lock
		  on that mutex. 
		</p>
 
	 </div>
 
	 <div class="section"><h2 class="sectiontitle">Non Solutions</h2> 
		 
		<p>Mistaken solutions are so often proposed that it is worth
		  understanding why they are wrong. 
		</p>
 
		<p>One common mistake is to assume that declaring the flag with the 
		  <samp class="codeph">volatile</samp> keyword solves the problem. Though the 
		  <samp class="codeph">volatile</samp> keyword forces a write to happen immediately,
		  it generally has no effect on the visible ordering of that write with respect
		  to other memory operations. An exception to this rule are processors from the
		  Intel&reg; Itanium&reg; processor family, which by convention assign acquire semantics
		  to 
		  <samp class="codeph">volatile</samp> reads and release semantics to volatile
		  writes. 
		</p>
 
		<p>Another mistake is to assume that conditionally executed code cannot
		  happen before the condition is tested. However, the compiler or hardware may
		  speculatively hoist the conditional code above the condition. 
		</p>
 
		<p>Similarly, it is a mistake to assume that a processor cannot read the
		  target of a pointer before reading the pointer. A modern processor does not
		  read individual values from main memory. It reads cache lines. The target of a
		  pointer may be in a cache line that has already been read before the pointer
		  was read, thus giving the appearance that the processor presciently read the
		  pointer target. 
		</p>
 
	 </div>
 
  </div>
 
  
<div class="familylinks">
<div class="parentlink"><strong>Parent topic:</strong>&nbsp;<a href="../../tbb_userguide/Design_Patterns/Design_Patterns.htm">Design Patterns</a></div>
</div>
<div class="See Also">
<h2>See Also</h2>
<div class="linklist">
<div><a href="Lazy_Initialization.htm#Lazy_Initialization">Lazy Initialization 
		  </a></div></div>
</div> 

</body>
</html>