<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Pwlane</id>
	<title>Expertiza_Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Pwlane"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Pwlane"/>
	<updated>2026-09-17T08:52:01Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_9&amp;diff=32402</id>
		<title>CSC/ECE 506 Spring 2010/ch 9</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_9&amp;diff=32402"/>
		<updated>2010-04-28T23:02:27Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In addition to a proper cache coherency model, it is also important for a multiprocessor system to provide support at the hardware level for synchronization.  The most common types of synchronization are locks and barriers, which are discussed in this chapter.  &lt;br /&gt;
&lt;br /&gt;
= Lock Implementations =&lt;br /&gt;
&lt;br /&gt;
Locks are an important concept when programming for multi core systems.  The basic concept of a lock is to protect the code inside the lock.  That is to be sure that while a certain thread X has entered the critical section, another thread Y is not also inside of the critical section and possibly modifying critical values.  When a lock is being used, while thread X has entered into the critical section, thread Y must wait until X has exited before entering.  This can be accomplished in a variety of ways of varying complexity and performance.&lt;br /&gt;
&lt;br /&gt;
== Performance Evaluation ==&lt;br /&gt;
&lt;br /&gt;
The Solihin text gives 4 methods to determine the performance of a lock implementation.  &lt;br /&gt;
&lt;br /&gt;
*Acquisition Latency - How much time does it take to acquire the lock?&lt;br /&gt;
&lt;br /&gt;
*Traffic - How much bus traffic is generated by threads attempting to acquire the lock?&lt;br /&gt;
&lt;br /&gt;
*Fairness - FIFO vs. Luck&lt;br /&gt;
&lt;br /&gt;
*Storage - How much storage is needed compared to the number of threads?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Atomic Instructions ==&lt;br /&gt;
&lt;br /&gt;
Since a multiprocessor system cannot disable interupts as an effective method to execute a bit of code atomically, there must be hardware support for atomic operations. [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
Being able to execute an atomic instruction is a requirement for most lock implementations.  It is important that when a processor attempts to set a lock either the lock is fully set and the thread is able to enter into the critical section, or the lock is not set, and it appears that none of the instructions required to set the lock have executed.  &lt;br /&gt;
&lt;br /&gt;
In the x86 instruction set the opcode CMPXCHG (meaning compare and exchange) can be used in a lock implementation in order to guarantee atomicity.  This function works by sending a destination and a source.  The accumulator is compared to the destination and if they are equal loaded with the source.  If they are NOT equal the accumulator is loaded with the destination value.  In order to assure that this is executed atomically the opcode must be issued with the LOCK prefix.  This is useful in implementing some locks, such as ticket locks.  [http://faydoc.tripod.com/cpu/cmpxchg.htm]&lt;br /&gt;
&lt;br /&gt;
== Hand-off Lock ==&lt;br /&gt;
&lt;br /&gt;
Another type of lock that is not discussed in the text is known as the &amp;quot;Hand-off&amp;quot; lock.  In this lock the first thread acquires the lock if no other thread is currently locked (since it is the first thread).  When another thread attempts to gain the lock it will see that the lock is in use and adds itself to the queue.  Once done this thread can sleep until called by the thread with the lock.  Once the thread in the lock is finished, it will pass the lock to the next thread in the queue.  [www.cs.duke.edu/~chase/cps110/slides/threads3.ppt]&lt;br /&gt;
&lt;br /&gt;
== Avoiding Locks ==&lt;br /&gt;
&lt;br /&gt;
There are many reasons why a programmer should attempt to write programs in such a way as to avoid locks if possible.  There are many problems that can arise with the use of locks. [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
One of the must well known issue is deadlock.  This can occur when the threads are waiting to acquire the lock, but the lock will never be unlocked.  For example if 2 threads are both spinning on a lock that is locked, they will continue to spin forever, as each thread 'thinks' that the other is inside the critical section.&lt;br /&gt;
&lt;br /&gt;
Another problem with using locks is that the performance is not optimal, as often a lock is used when there is only a chance of conflict.  This approach to programming yields slower performance than what might be possible with other methods.  This also leads to questions of granularity, that is how much of the code should be protected under the critical section.  The programmer must decide between many small (fine grain) locks or fewer, more encompassing locks.  This decision can greatly effect the performance of the program. Lock (computer science) [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
= Barrier Implementations =&lt;br /&gt;
&lt;br /&gt;
In many ways, barriers are simpler than locks.  A barrier simply is a point in a program where one or more threads must reach before the parallel program is allowed to continue.  When using barriers a programmer does not have to be concerned with advanced topics such as fairness, that are required when programming for locks.&lt;br /&gt;
&lt;br /&gt;
== Performance Evaluation ==&lt;br /&gt;
&lt;br /&gt;
The Solihin text gives 2 metrics for which the performance of a barrier implementation should be evaluated.&lt;br /&gt;
&lt;br /&gt;
*Latency - The time required to enter and exit a barrier.&lt;br /&gt;
&lt;br /&gt;
*Traffic - Communications overhead required by the barrier.&lt;br /&gt;
&lt;br /&gt;
== Sense-Reversal Barrier ==&lt;br /&gt;
&lt;br /&gt;
This barrier is a centralized barrier where a single count variable protected by a lock is shared among all the threads. Each thread on reaching the barrier increments its value and waits till the value of variable has reached the number of threads for which barrier was implemented.&lt;br /&gt;
&lt;br /&gt;
Since all the threads are spinning around a single variable the miss rate is scales quadratically with number of processors.&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki01.png]]&lt;br /&gt;
[http://www.ukhec.ac.uk/publications/reports/synch_java.pdf]&lt;br /&gt;
&lt;br /&gt;
== Combining Tree Barrier ==&lt;br /&gt;
&lt;br /&gt;
This barrier is a distributed barrier where group of processors form clusters and updates value of a local variable. The local variable on reaching a value equal to number of threads updating it, proceeds to increment another variable higher in hierarchy in the combining tree. When the variable in the highest level of hierarchy in the combining tree reaches its max value it is considered that all the threads have reached the barrier and synchronization is complete.&lt;br /&gt;
&lt;br /&gt;
Since in this case all the threads are updated local variables in form of smaller groups the miss rate is not as high as sense-reversal barrier.&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the operation of combining tree barrier with threads grouped in two groups. The variables C0 and C1 are local to each group and C2 is the variable that is at higher level of hierarchy in the tree.&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki02.png]]&lt;br /&gt;
[http://www.ukhec.ac.uk/publications/reports/synch_java.pdf]&lt;br /&gt;
&lt;br /&gt;
== Tournament Barrier ==&lt;br /&gt;
&lt;br /&gt;
In tournament barrier the threads are considered to be leaves at the end of a binary tree and each node represents a flag. Two threads compete with each other and the looser thread is allowed to set the flag and move to higher level and compete to loose with the looser thread from other section of binary tree. Thus the thread which completes last is able to set the highest flag in the binary tree. On setting the flag it indicates to all the threads that barrier has been completed and thus synchronization is achieved.&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki03.png]]&lt;br /&gt;
[http://www.ukhec.ac.uk/publications/reports/synch_java.pdf]&lt;br /&gt;
&lt;br /&gt;
== Disseminating Barrier ==&lt;br /&gt;
&lt;br /&gt;
In this barrier each thread maintains a record of the activity of other threads. For every round i with n threads, thread A notifies thread (A + 2i) mod n. Thus after logn rounds all the threads are aware of the status of every other thread running and whether it has reached the barrier.&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki04.png]]&lt;br /&gt;
[http://www.cs.brown.edu/courses/cs176/barrier.ppt]&lt;br /&gt;
&lt;br /&gt;
== Performance Comparison ==&lt;br /&gt;
&lt;br /&gt;
Additive Schwarz Preconditioned Conjugate Gradient (ASPCG) kernal on Altix System&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki05.png]]&lt;br /&gt;
&lt;br /&gt;
Figure shows the timings of the ASPCG kernel using the different barrier implementations. It can be seen that the blocking barrier does not scale with number of threads as with increase in number of threads the contention increases. [http://www2.cs.uh.edu/~hpctools/pub/iwomp-barrier.pdf]&lt;br /&gt;
&lt;br /&gt;
EPCC Microbenchmark&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki06.png]]&lt;br /&gt;
&lt;br /&gt;
Figure shows the timings to implement a barrier of the EPCC Microbenchmark using the different barrier implementations. It can be seen that the blocking barrier/centralized blocking barrier does not scale with number of threads as with increase in number of threads the contention increases. [http://www2.cs.uh.edu/~hpctools/pub/iwomp-barrier.pdf]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
&lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
* CMPXCHG - Compare and Exchange [http://faydoc.tripod.com/cpu/cmpxchg.htm]&lt;br /&gt;
* Lock (computer science) [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
* www.cs.duke.edu/~chase/cps110/slides/threads3.ppt  [www.cs.duke.edu/~chase/cps110/slides/threads3.ppt]&lt;br /&gt;
* Deadlock [http://www.statemaster.com/encyclopedia/Deadlock]&lt;br /&gt;
* Barrier Synchronization in Java, Carwyn Ball and Mark Bull [http://www.ukhec.ac.uk/publications/reports/synch_java.pdf]&lt;br /&gt;
* www.cs.brown.edu/courses/cs176/barrier.ppt [http://www.cs.brown.edu/courses/cs176/barrier.ppt]&lt;br /&gt;
* Scalability evaluation of barrier algorithms for OpenMP [http://www2.cs.uh.edu/~hpctools/pub/iwomp-barrier.pdf]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_9&amp;diff=32401</id>
		<title>CSC/ECE 506 Spring 2010/ch 9</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_9&amp;diff=32401"/>
		<updated>2010-04-28T22:57:19Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In addition to a proper cache coherency model, it is also important for a multiprocessor system to provide support at the hardware level for synchronization.  The most common types of synchronization are locks and barriers, which are discussed in this chapter.  &lt;br /&gt;
&lt;br /&gt;
= Lock Implementations =&lt;br /&gt;
&lt;br /&gt;
Locks are an important concept when programming for multi core systems.  The basic concept of a lock is to protect the code inside the lock.  That is to be sure that while a certain thread X has entered the critical section, another thread Y is not also inside of the critical section and possibly modifying critical values.  When a lock is being used, while thread X has entered into the critical section, thread Y must wait until X has exited before entering.  This can be accomplished in a variety of ways of varying complexity and performance.&lt;br /&gt;
&lt;br /&gt;
== Performance Evaluation ==&lt;br /&gt;
&lt;br /&gt;
The Solihin text gives 4 methods to determine the performance of a lock implementation.  &lt;br /&gt;
&lt;br /&gt;
*Acquisition Latency - How much time does it take to acquire the lock?&lt;br /&gt;
&lt;br /&gt;
*Traffic - How much bus traffic is generated by threads attempting to acquire the lock?&lt;br /&gt;
&lt;br /&gt;
*Fairness - FIFO vs. Luck&lt;br /&gt;
&lt;br /&gt;
*Storage - How much storage is needed compared to the number of threads?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Atomic Instructions ==&lt;br /&gt;
&lt;br /&gt;
Since a multiprocessor system cannot disable interupts as an effective method to execute a bit of code atomically, there must be hardware support for atomic operations. [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
Being able to execute an atomic instruction is a requirement for most lock implementations.  It is important that when a processor attempts to set a lock either the lock is fully set and the thread is able to enter into the critical section, or the lock is not set, and it appears that none of the instructions required to set the lock have executed.  &lt;br /&gt;
&lt;br /&gt;
In the x86 instruction set the opcode CMPXCHG (meaning compare and exchange) can be used in a lock implementation in order to guarantee atomicity.  This function works by sending a destination and a source.  The accumulator is compared to the destination and if they are equal loaded with the source.  If they are NOT equal the accumulator is loaded with the destination value.  In order to assure that this is executed atomically the opcode must be issued with the LOCK prefix.  This is useful in implementing some locks, such as ticket locks.  [http://faydoc.tripod.com/cpu/cmpxchg.htm]&lt;br /&gt;
&lt;br /&gt;
== Hand-off Lock ==&lt;br /&gt;
&lt;br /&gt;
Another type of lock that is not discussed in the text is known as the &amp;quot;Hand-off&amp;quot; lock.  In this lock the first thread acquires the lock if no other thread is currently locked (since it is the first thread).  When another thread attempts to gain the lock it will see that the lock is in use and adds itself to the queue.  Once done this thread can sleep until called by the thread with the lock.  Once the thread in the lock is finished, it will pass the lock to the next thread in the queue.  [www.cs.duke.edu/~chase/cps110/slides/threads3.ppt]&lt;br /&gt;
&lt;br /&gt;
== Avoiding Locks ==&lt;br /&gt;
&lt;br /&gt;
There are many reasons why a programmer should attempt to write programs in such a way as to avoid locks if possible.  There are many problems that can arise with the use of locks. [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
One of the must well known issue is deadlock.  This can occur when the threads are waiting to acquire the lock, but the lock will never be unlocked.  For example if 2 threads are both spinning on a lock that is locked, they will continue to spin forever, as each thread 'thinks' that the other is inside the critical section.&lt;br /&gt;
&lt;br /&gt;
Another problem with using locks is that the performance is not optimal, as often a lock is used when there is only a chance of conflict.  This approach to programming yields slower performance than what might be possible with other methods.  This also leads to questions of granularity, that is how much of the code should be protected under the critical section.  The programmer must decide between many small (fine grain) locks or fewer, more encompassing locks.  This decision can greatly effect the performance of the program. Lock (computer science) [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
= Barrier Implementations =&lt;br /&gt;
&lt;br /&gt;
== Sense-Reversal Barrier ==&lt;br /&gt;
&lt;br /&gt;
This barrier is a centralized barrier where a single count variable protected by a lock is shared among all the threads. Each thread on reaching the barrier increments its value and waits till the value of variable has reached the number of threads for which barrier was implemented.&lt;br /&gt;
&lt;br /&gt;
Since all the threads are spinning around a single variable the miss rate is scales quadratically with number of processors.&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki01.png]]&lt;br /&gt;
[http://www.ukhec.ac.uk/publications/reports/synch_java.pdf]&lt;br /&gt;
&lt;br /&gt;
== Combining Tree Barrier ==&lt;br /&gt;
&lt;br /&gt;
This barrier is a distributed barrier where group of processors form clusters and updates value of a local variable. The local variable on reaching a value equal to number of threads updating it, proceeds to increment another variable higher in hierarchy in the combining tree. When the variable in the highest level of hierarchy in the combining tree reaches its max value it is considered that all the threads have reached the barrier and synchronization is complete.&lt;br /&gt;
&lt;br /&gt;
Since in this case all the threads are updated local variables in form of smaller groups the miss rate is not as high as sense-reversal barrier.&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the operation of combining tree barrier with threads grouped in two groups. The variables C0 and C1 are local to each group and C2 is the variable that is at higher level of hierarchy in the tree.&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki02.png]]&lt;br /&gt;
[http://www.ukhec.ac.uk/publications/reports/synch_java.pdf]&lt;br /&gt;
&lt;br /&gt;
== Tournament Barrier ==&lt;br /&gt;
&lt;br /&gt;
In tournament barrier the threads are considered to be leaves at the end of a binary tree and each node represents a flag. Two threads compete with each other and the looser thread is allowed to set the flag and move to higher level and compete to loose with the looser thread from other section of binary tree. Thus the thread which completes last is able to set the highest flag in the binary tree. On setting the flag it indicates to all the threads that barrier has been completed and thus synchronization is achieved.&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki03.png]]&lt;br /&gt;
[http://www.ukhec.ac.uk/publications/reports/synch_java.pdf]&lt;br /&gt;
&lt;br /&gt;
== Disseminating Barrier ==&lt;br /&gt;
&lt;br /&gt;
In this barrier each thread maintains a record of the activity of other threads. For every round i with n threads, thread A notifies thread (A + 2i) mod n. Thus after logn rounds all the threads are aware of the status of every other thread running and whether it has reached the barrier.&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki04.png]]&lt;br /&gt;
[http://www.cs.brown.edu/courses/cs176/barrier.ppt]&lt;br /&gt;
&lt;br /&gt;
== Performance Comparison ==&lt;br /&gt;
&lt;br /&gt;
Additive Schwarz Preconditioned Conjugate Gradient (ASPCG) kernal on Altix System&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki05.png]]&lt;br /&gt;
&lt;br /&gt;
Figure shows the timings of the ASPCG kernel using the different barrier implementations. It can be seen that the blocking barrier does not scale with number of threads as with increase in number of threads the contention increases. [http://www2.cs.uh.edu/~hpctools/pub/iwomp-barrier.pdf]&lt;br /&gt;
&lt;br /&gt;
EPCC Microbenchmark&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki06.png]]&lt;br /&gt;
&lt;br /&gt;
Figure shows the timings to implement a barrier of the EPCC Microbenchmark using the different barrier implementations. It can be seen that the blocking barrier/centralized blocking barrier does not scale with number of threads as with increase in number of threads the contention increases. [http://www2.cs.uh.edu/~hpctools/pub/iwomp-barrier.pdf]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
&lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
* CMPXCHG - Compare and Exchange [http://faydoc.tripod.com/cpu/cmpxchg.htm]&lt;br /&gt;
* Lock (computer science) [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
* www.cs.duke.edu/~chase/cps110/slides/threads3.ppt  [www.cs.duke.edu/~chase/cps110/slides/threads3.ppt]&lt;br /&gt;
* Deadlock [http://www.statemaster.com/encyclopedia/Deadlock]&lt;br /&gt;
* Barrier Synchronization in Java, Carwyn Ball and Mark Bull [http://www.ukhec.ac.uk/publications/reports/synch_java.pdf]&lt;br /&gt;
* www.cs.brown.edu/courses/cs176/barrier.ppt [http://www.cs.brown.edu/courses/cs176/barrier.ppt]&lt;br /&gt;
* Scalability evaluation of barrier algorithms for OpenMP [http://www2.cs.uh.edu/~hpctools/pub/iwomp-barrier.pdf]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_9&amp;diff=32400</id>
		<title>CSC/ECE 506 Spring 2010/ch 9</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_9&amp;diff=32400"/>
		<updated>2010-04-26T21:49:33Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In addition to a proper cache coherency model, it is also important for a multiprocessor system to provide support at the hardware level for synchronization.  The most common types of synchronization are locks and barriers, which are discussed in this chapter.  &lt;br /&gt;
&lt;br /&gt;
= Lock Implementations =&lt;br /&gt;
&lt;br /&gt;
Locks are an important concept when programming for multi core systems.  The basic concept of a lock is to protect the code inside the lock.  That is to be sure that while a certain thread X has entered the critical section, another thread Y is not also inside of the critical section and possibly modifying critical values.  When a lock is being used, while thread X has entered into the critical section, thread Y must wait until X has exited before entering.  This can be accomplished in a variety of ways of varying complexity and performance.&lt;br /&gt;
&lt;br /&gt;
== Performance Evaluation&lt;br /&gt;
&lt;br /&gt;
The Solihin text gives 4 methods to determine the performance of a lock implementation.  &lt;br /&gt;
&lt;br /&gt;
*Acquisition Latency - How much time does it take to acquire the lock?&lt;br /&gt;
&lt;br /&gt;
*Traffic - How much bus traffic is generated by threads attempting to acquire the lock?&lt;br /&gt;
&lt;br /&gt;
*Fairness - FIFO vs. Luck&lt;br /&gt;
&lt;br /&gt;
*Storage - How much storage is needed compared to the number of threads?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Atomic Instructions ==&lt;br /&gt;
&lt;br /&gt;
Since a multiprocessor system cannot disable interupts as an effective method to execute a bit of code atomically, there must be hardware support for atomic operations. [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
Being able to execute an atomic instruction is a requirement for most lock implementations.  It is important that when a processor attempts to set a lock either the lock is fully set and the thread is able to enter into the critical section, or the lock is not set, and it appears that none of the instructions required to set the lock have executed.  &lt;br /&gt;
&lt;br /&gt;
In the x86 instruction set the opcode CMPXCHG (meaning compare and exchange) can be used in a lock implementation in order to guarantee atomicity.  This function works by sending a destination and a source.  The accumulator is compared to the destination and if they are equal loaded with the source.  If they are NOT equal the accumulator is loaded with the destination value.  In order to assure that this is executed atomically the opcode must be issued with the LOCK prefix.  This is useful in implementing some locks, such as ticket locks.  [http://faydoc.tripod.com/cpu/cmpxchg.htm]&lt;br /&gt;
&lt;br /&gt;
== Hand-off Lock ==&lt;br /&gt;
&lt;br /&gt;
Another type of lock that is not discussed in the text is known as the &amp;quot;Hand-off&amp;quot; lock.  In this lock the first thread acquires the lock if no other thread is currently locked (since it is the first thread).  When another thread attempts to gain the lock it will see that the lock is in use and adds itself to the queue.  Once done this thread can sleep until called by the thread with the lock.  Once the thread in the lock is finished, it will pass the lock to the next thread in the queue.  [www.cs.duke.edu/~chase/cps110/slides/threads3.ppt]&lt;br /&gt;
&lt;br /&gt;
== Avoiding Locks ==&lt;br /&gt;
&lt;br /&gt;
There are many reasons why a programmer should attempt to write programs in such a way as to avoid locks if possible.  There are many problems that can arise with the use of locks. [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
One of the must well known issue is deadlock.  This can occur when the threads are waiting to acquire the lock, but the lock will never be unlocked.  For example if 2 threads are both spinning on a lock that is locked, they will continue to spin forever, as each thread 'thinks' that the other is inside the critical section.&lt;br /&gt;
&lt;br /&gt;
Another problem with using locks is that the performance is not optimal, as often a lock is used when there is only a chance of conflict.  This approach to programming yields slower performance than what might be possible with other methods.  This also leads to questions of granularity, that is how much of the code should be protected under the critical section.  The programmer must decide between many small (fine grain) locks or fewer, more encompassing locks.  This decision can greatly effect the performance of the program. Lock (computer science) [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
= Barrier Implementations =&lt;br /&gt;
&lt;br /&gt;
== Sense-Reversal Barrier ==&lt;br /&gt;
&lt;br /&gt;
This barrier is a centralized barrier where a single count variable protected by a lock is shared among all the threads. Each thread on reaching the barrier increments its value and waits till the value of variable has reached the number of threads for which barrier was implemented.&lt;br /&gt;
&lt;br /&gt;
Since all the threads are spinning around a single variable the miss rate is scales quadratically with number of processors.&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki01.png]]&lt;br /&gt;
[http://www.ukhec.ac.uk/publications/reports/synch_java.pdf]&lt;br /&gt;
&lt;br /&gt;
== Combining Tree Barrier ==&lt;br /&gt;
&lt;br /&gt;
This barrier is a distributed barrier where group of processors form clusters and updates value of a local variable. The local variable on reaching a value equal to number of threads updating it, proceeds to increment another variable higher in hierarchy in the combining tree. When the variable in the highest level of hierarchy in the combining tree reaches its max value it is considered that all the threads have reached the barrier and synchronization is complete.&lt;br /&gt;
&lt;br /&gt;
Since in this case all the threads are updated local variables in form of smaller groups the miss rate is not as high as sense-reversal barrier.&lt;br /&gt;
&lt;br /&gt;
The diagram below shows the operation of combining tree barrier with threads grouped in two groups. The variables C0 and C1 are local to each group and C2 is the variable that is at higher level of hierarchy in the tree.&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki02.png]]&lt;br /&gt;
[http://www.ukhec.ac.uk/publications/reports/synch_java.pdf]&lt;br /&gt;
&lt;br /&gt;
== Tournament Barrier ==&lt;br /&gt;
&lt;br /&gt;
In tournament barrier the threads are considered to be leaves at the end of a binary tree and each node represents a flag. Two threads compete with each other and the looser thread is allowed to set the flag and move to higher level and compete to loose with the looser thread from other section of binary tree. Thus the thread which completes last is able to set the highest flag in the binary tree. On setting the flag it indicates to all the threads that barrier has been completed and thus synchronization is achieved.&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki03.png]]&lt;br /&gt;
[http://www.ukhec.ac.uk/publications/reports/synch_java.pdf]&lt;br /&gt;
&lt;br /&gt;
== Disseminating Barrier ==&lt;br /&gt;
&lt;br /&gt;
In this barrier each thread maintains a record of the activity of other threads. For every round i with n threads, thread A notifies thread (A + 2i) mod n. Thus after logn rounds all the threads are aware of the status of every other thread running and whether it has reached the barrier.&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki04.png]]&lt;br /&gt;
[http://www.cs.brown.edu/courses/cs176/barrier.ppt]&lt;br /&gt;
&lt;br /&gt;
== Performance Comparison ==&lt;br /&gt;
&lt;br /&gt;
Additive Schwarz Preconditioned Conjugate Gradient (ASPCG) kernal on Altix System&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki05.png]]&lt;br /&gt;
&lt;br /&gt;
Figure shows the timings of the ASPCG kernel using the different barrier implementations. It can be seen that the blocking barrier does not scale with number of threads as with increase in number of threads the contention increases. [http://www2.cs.uh.edu/~hpctools/pub/iwomp-barrier.pdf]&lt;br /&gt;
&lt;br /&gt;
EPCC Microbenchmark&lt;br /&gt;
&lt;br /&gt;
[[Image:Ch9wiki06.png]]&lt;br /&gt;
&lt;br /&gt;
Figure shows the timings to implement a barrier of the EPCC Microbenchmark using the different barrier implementations. It can be seen that the blocking barrier/centralized blocking barrier does not scale with number of threads as with increase in number of threads the contention increases. [http://www2.cs.uh.edu/~hpctools/pub/iwomp-barrier.pdf]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
&lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
* CMPXCHG - Compare and Exchange [http://faydoc.tripod.com/cpu/cmpxchg.htm]&lt;br /&gt;
* Lock (computer science) [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
* www.cs.duke.edu/~chase/cps110/slides/threads3.ppt  [www.cs.duke.edu/~chase/cps110/slides/threads3.ppt]&lt;br /&gt;
* Deadlock [http://www.statemaster.com/encyclopedia/Deadlock]&lt;br /&gt;
* Barrier Synchronization in Java, Carwyn Ball and Mark Bull [http://www.ukhec.ac.uk/publications/reports/synch_java.pdf]&lt;br /&gt;
* www.cs.brown.edu/courses/cs176/barrier.ppt [http://www.cs.brown.edu/courses/cs176/barrier.ppt]&lt;br /&gt;
* Scalability evaluation of barrier algorithms for OpenMP [http://www2.cs.uh.edu/~hpctools/pub/iwomp-barrier.pdf]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Ch9wiki06.png&amp;diff=32399</id>
		<title>File:Ch9wiki06.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Ch9wiki06.png&amp;diff=32399"/>
		<updated>2010-04-26T21:40:04Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Ch9wiki05.png&amp;diff=32398</id>
		<title>File:Ch9wiki05.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Ch9wiki05.png&amp;diff=32398"/>
		<updated>2010-04-26T21:39:53Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Ch9wiki04.png&amp;diff=32397</id>
		<title>File:Ch9wiki04.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Ch9wiki04.png&amp;diff=32397"/>
		<updated>2010-04-26T21:39:38Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Ch9wiki03.png&amp;diff=32396</id>
		<title>File:Ch9wiki03.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Ch9wiki03.png&amp;diff=32396"/>
		<updated>2010-04-26T21:39:25Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Ch9wiki02.png&amp;diff=32395</id>
		<title>File:Ch9wiki02.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Ch9wiki02.png&amp;diff=32395"/>
		<updated>2010-04-26T21:39:13Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=File:Ch9wiki01.png&amp;diff=32394</id>
		<title>File:Ch9wiki01.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=File:Ch9wiki01.png&amp;diff=32394"/>
		<updated>2010-04-26T21:39:00Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_9&amp;diff=32393</id>
		<title>CSC/ECE 506 Spring 2010/ch 9</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_9&amp;diff=32393"/>
		<updated>2010-04-26T18:25:10Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In addition to a proper cache coherency model, it is also important for a multiprocessor system to provide support at the hardware level for synchronization.  The most common types of synchronization are locks and barriers, which are discussed in this chapter.  &lt;br /&gt;
&lt;br /&gt;
= Lock Implementations =&lt;br /&gt;
&lt;br /&gt;
Locks are an important concept when programming for multi core systems.  The basic concept of a lock is to protect the code inside the lock.  That is to be sure that while a certain thread X has entered the critical section, another thread Y is not also inside of the critical section and possibly modifying critical values.  When a lock is being used, while thread X has entered into the critical section, thread Y must wait until X has exited before entering.  This can be accomplished in a variety of ways of varying complexity and performance.&lt;br /&gt;
&lt;br /&gt;
== Performance Evaluation ==&lt;br /&gt;
&lt;br /&gt;
The Solihin text gives 4 methods to determine the performance of a lock implementation.  &lt;br /&gt;
&lt;br /&gt;
*Acquisition Latency - How much time does it take to acquire the lock?&lt;br /&gt;
&lt;br /&gt;
*Traffic - How much bus traffic is generated by threads attempting to acquire the lock?&lt;br /&gt;
&lt;br /&gt;
*Fairness - FIFO vs. Luck&lt;br /&gt;
&lt;br /&gt;
*Storage - How much storage is needed compared to the number of threads?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Atomic Instructions ==&lt;br /&gt;
&lt;br /&gt;
Since a multiprocessor system cannot disable interupts as an effective method to execute a bit of code atomically, there must be hardware support for atomic operations. [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
Being able to execute an atomic instruction is a requirement for most lock implementations.  It is important that when a processor attempts to set a lock either the lock is fully set and the thread is able to enter into the critical section, or the lock is not set, and it appears that none of the instructions required to set the lock have executed.  &lt;br /&gt;
&lt;br /&gt;
In the x86 instruction set the opcode CMPXCHG (meaning compare and exchange) can be used in a lock implementation in order to guarantee atomicity.  This function works by sending a destination and a source.  The accumulator is compared to the destination and if they are equal loaded with the source.  If they are NOT equal the accumulator is loaded with the destination value.  In order to assure that this is executed atomically the opcode must be issued with the LOCK prefix.  This is useful in implementing some locks, such as ticket locks.  [http://faydoc.tripod.com/cpu/cmpxchg.htm]&lt;br /&gt;
&lt;br /&gt;
== Hand-off Lock ==&lt;br /&gt;
&lt;br /&gt;
Another type of lock that is not discussed in the text is known as the &amp;quot;Hand-off&amp;quot; lock.  In this lock the first thread acquires the lock if no other thread is currently locked (since it is the first thread).  When another thread attempts to gain the lock it will see that the lock is in use and adds itself to the queue.  Once done this thread can sleep until called by the thread with the lock.  Once the thread in the lock is finished, it will pass the lock to the next thread in the queue.  [http://www.cs.duke.edu/~chase/cps110/slides/threads3.ppt]&lt;br /&gt;
&lt;br /&gt;
== Avoiding Locks ==&lt;br /&gt;
&lt;br /&gt;
There are many reasons why a programmer should attempt to write programs in such a way as to avoid locks if possible.  There are many problems that can arise with the use of locks. [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
One of the must well known issue is deadlock.  This can occur when the threads are waiting to acquire the lock, but the lock will never be unlocked.  For example if 2 threads are both spinning on a lock that is locked, they will continue to spin forever, as each thread 'thinks' that the other is inside the critical section.&lt;br /&gt;
&lt;br /&gt;
Another problem with using locks is that the performance is not optimal, as often a lock is used when there is only a chance of conflict.  This approach to programming yields slower performance than what might be possible with other methods.  This also leads to questions of granularity, that is how much of the code should be protected under the critical section.  The programmer must decide between many small (fine grain) locks or fewer, more encompassing locks.  This decision can greatly effect the performance of the program. Lock (computer science) [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
= Barrier Implementations =&lt;br /&gt;
&lt;br /&gt;
Partners Work Not Received&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
&lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
* CMPXCHG - Compare and Exchange [http://faydoc.tripod.com/cpu/cmpxchg.htm]&lt;br /&gt;
* Lock (computer science) [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
* www.cs.duke.edu/~chase/cps110/slides/threads3.ppt  [http://www.cs.duke.edu/~chase/cps110/slides/threads3.ppt]&lt;br /&gt;
* Deadlock [http://www.statemaster.com/encyclopedia/Deadlock]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_9&amp;diff=32392</id>
		<title>CSC/ECE 506 Spring 2010/ch 9</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_9&amp;diff=32392"/>
		<updated>2010-04-26T18:24:31Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In addition to a proper cache coherency model, it is also important for a multiprocessor system to provide support at the hardware level for synchronization.  The most common types of synchronization are locks and barriers, which are discussed in this chapter.  &lt;br /&gt;
&lt;br /&gt;
= Lock Implementations =&lt;br /&gt;
&lt;br /&gt;
Locks are an important concept when programming for multi core systems.  The basic concept of a lock is to protect the code inside the lock.  That is to be sure that while a certain thread X has entered the critical section, another thread Y is not also inside of the critical section and possibly modifying critical values.  When a lock is being used, while thread X has entered into the critical section, thread Y must wait until X has exited before entering.  This can be accomplished in a variety of ways of varying complexity and performance.&lt;br /&gt;
&lt;br /&gt;
== Performance Evaluation ==&lt;br /&gt;
&lt;br /&gt;
The Solihin text gives 4 methods to determine the performance of a lock implementation.  &lt;br /&gt;
&lt;br /&gt;
*Acquisition Latency - How much time does it take to acquire the lock?&lt;br /&gt;
&lt;br /&gt;
*Traffic - How much bus traffic is generated by threads attempting to acquire the lock?&lt;br /&gt;
&lt;br /&gt;
*Fairness - FIFO vs. Luck&lt;br /&gt;
&lt;br /&gt;
*Storage - How much storage is needed compared to the number of threads?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Atomic Instructions ==&lt;br /&gt;
&lt;br /&gt;
Since a multiprocessor system cannot disable interupts as an effective method to execute a bit of code atomically, there must be hardware support for atomic operations. [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
Being able to execute an atomic instruction is a requirement for most lock implementations.  It is important that when a processor attempts to set a lock either the lock is fully set and the thread is able to enter into the critical section, or the lock is not set, and it appears that none of the instructions required to set the lock have executed.  &lt;br /&gt;
&lt;br /&gt;
In the x86 instruction set the opcode CMPXCHG (meaning compare and exchange) can be used in a lock implementation in order to guarantee atomicity.  This function works by sending a destination and a source.  The accumulator is compared to the destination and if they are equal loaded with the source.  If they are NOT equal the accumulator is loaded with the destination value.  In order to assure that this is executed atomically the opcode must be issued with the LOCK prefix.  This is useful in implementing some locks, such as ticket locks.  [http://faydoc.tripod.com/cpu/cmpxchg.htm]&lt;br /&gt;
&lt;br /&gt;
== Hand-off Lock ==&lt;br /&gt;
&lt;br /&gt;
Another type of lock that is not discussed in the text is known as the &amp;quot;Hand-off&amp;quot; lock.  In this lock the first thread acquires the lock if no other thread is currently locked (since it is the first thread).  When another thread attempts to gain the lock it will see that the lock is in use and adds itself to the queue.  Once done this thread can sleep until called by the thread with the lock.  Once the thread in the lock is finished, it will pass the lock to the next thread in the queue.  [www.cs.duke.edu/~chase/cps110/slides/threads3.ppt]&lt;br /&gt;
&lt;br /&gt;
== Avoiding Locks ==&lt;br /&gt;
&lt;br /&gt;
There are many reasons why a programmer should attempt to write programs in such a way as to avoid locks if possible.  There are many problems that can arise with the use of locks. [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
One of the must well known issue is deadlock.  This can occur when the threads are waiting to acquire the lock, but the lock will never be unlocked.  For example if 2 threads are both spinning on a lock that is locked, they will continue to spin forever, as each thread 'thinks' that the other is inside the critical section.&lt;br /&gt;
&lt;br /&gt;
Another problem with using locks is that the performance is not optimal, as often a lock is used when there is only a chance of conflict.  This approach to programming yields slower performance than what might be possible with other methods.  This also leads to questions of granularity, that is how much of the code should be protected under the critical section.  The programmer must decide between many small (fine grain) locks or fewer, more encompassing locks.  This decision can greatly effect the performance of the program. Lock (computer science) [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
= Barrier Implementations =&lt;br /&gt;
&lt;br /&gt;
Partners Work Not Received&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
&lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
* CMPXCHG - Compare and Exchange [http://faydoc.tripod.com/cpu/cmpxchg.htm]&lt;br /&gt;
* Lock (computer science) [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
* www.cs.duke.edu/~chase/cps110/slides/threads3.ppt  [www.cs.duke.edu/~chase/cps110/slides/threads3.ppt]&lt;br /&gt;
* Deadlock [http://www.statemaster.com/encyclopedia/Deadlock]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_9&amp;diff=32391</id>
		<title>CSC/ECE 506 Spring 2010/ch 9</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_9&amp;diff=32391"/>
		<updated>2010-04-26T18:24:15Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In addition to a proper cache coherency model, it is also important for a multiprocessor system to provide support at the hardware level for synchronization.  The most common types of synchronization are locks and barriers, which are discussed in this chapter.  &lt;br /&gt;
&lt;br /&gt;
= Lock Implementations =&lt;br /&gt;
&lt;br /&gt;
Locks are an important concept when programming for multi core systems.  The basic concept of a lock is to protect the code inside the lock.  That is to be sure that while a certain thread X has entered the critical section, another thread Y is not also inside of the critical section and possibly modifying critical values.  When a lock is being used, while thread X has entered into the critical section, thread Y must wait until X has exited before entering.  This can be accomplished in a variety of ways of varying complexity and performance.&lt;br /&gt;
&lt;br /&gt;
== Performance Evaluation&lt;br /&gt;
&lt;br /&gt;
The Solihin text gives 4 methods to determine the performance of a lock implementation.  &lt;br /&gt;
&lt;br /&gt;
*Acquisition Latency - How much time does it take to acquire the lock?&lt;br /&gt;
&lt;br /&gt;
*Traffic - How much bus traffic is generated by threads attempting to acquire the lock?&lt;br /&gt;
&lt;br /&gt;
*Fairness - FIFO vs. Luck&lt;br /&gt;
&lt;br /&gt;
*Storage - How much storage is needed compared to the number of threads?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Atomic Instructions ==&lt;br /&gt;
&lt;br /&gt;
Since a multiprocessor system cannot disable interupts as an effective method to execute a bit of code atomically, there must be hardware support for atomic operations. [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
Being able to execute an atomic instruction is a requirement for most lock implementations.  It is important that when a processor attempts to set a lock either the lock is fully set and the thread is able to enter into the critical section, or the lock is not set, and it appears that none of the instructions required to set the lock have executed.  &lt;br /&gt;
&lt;br /&gt;
In the x86 instruction set the opcode CMPXCHG (meaning compare and exchange) can be used in a lock implementation in order to guarantee atomicity.  This function works by sending a destination and a source.  The accumulator is compared to the destination and if they are equal loaded with the source.  If they are NOT equal the accumulator is loaded with the destination value.  In order to assure that this is executed atomically the opcode must be issued with the LOCK prefix.  This is useful in implementing some locks, such as ticket locks.  [http://faydoc.tripod.com/cpu/cmpxchg.htm]&lt;br /&gt;
&lt;br /&gt;
== Hand-off Lock ==&lt;br /&gt;
&lt;br /&gt;
Another type of lock that is not discussed in the text is known as the &amp;quot;Hand-off&amp;quot; lock.  In this lock the first thread acquires the lock if no other thread is currently locked (since it is the first thread).  When another thread attempts to gain the lock it will see that the lock is in use and adds itself to the queue.  Once done this thread can sleep until called by the thread with the lock.  Once the thread in the lock is finished, it will pass the lock to the next thread in the queue.  [www.cs.duke.edu/~chase/cps110/slides/threads3.ppt]&lt;br /&gt;
&lt;br /&gt;
== Avoiding Locks ==&lt;br /&gt;
&lt;br /&gt;
There are many reasons why a programmer should attempt to write programs in such a way as to avoid locks if possible.  There are many problems that can arise with the use of locks. [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
One of the must well known issue is deadlock.  This can occur when the threads are waiting to acquire the lock, but the lock will never be unlocked.  For example if 2 threads are both spinning on a lock that is locked, they will continue to spin forever, as each thread 'thinks' that the other is inside the critical section.&lt;br /&gt;
&lt;br /&gt;
Another problem with using locks is that the performance is not optimal, as often a lock is used when there is only a chance of conflict.  This approach to programming yields slower performance than what might be possible with other methods.  This also leads to questions of granularity, that is how much of the code should be protected under the critical section.  The programmer must decide between many small (fine grain) locks or fewer, more encompassing locks.  This decision can greatly effect the performance of the program. Lock (computer science) [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
&lt;br /&gt;
= Barrier Implementations =&lt;br /&gt;
&lt;br /&gt;
Partners Work Not Received&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
&lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
* CMPXCHG - Compare and Exchange [http://faydoc.tripod.com/cpu/cmpxchg.htm]&lt;br /&gt;
* Lock (computer science) [http://www.statemaster.com/encyclopedia/Lock-(computer-science)]&lt;br /&gt;
* www.cs.duke.edu/~chase/cps110/slides/threads3.ppt  [www.cs.duke.edu/~chase/cps110/slides/threads3.ppt]&lt;br /&gt;
* Deadlock [http://www.statemaster.com/encyclopedia/Deadlock]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31537</id>
		<title>CSC/ECE 506 Spring 2010/ch 7 pl/</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31537"/>
		<updated>2010-04-05T20:05:44Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: /* Other Methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Shared-memory multiprocessors run into several problems that are more pronounced than their uniprocessor counterparts.  The Solihin text used in this course goes into detail on three of these issues, that is cache coherence, memory consistency and synchronization.  It is the goal of this wiki supplement to discuss these three issues and also what can be done to ensure that instructions are handled in both a timely and efficient manner and in a manner that is consistent with what the programmer might desire.&lt;br /&gt;
&lt;br /&gt;
= Cache Coherence =&lt;br /&gt;
&lt;br /&gt;
This problem arises when each chip in the system has its own separate and discrete cache.  The Solihin text gives a good example on how a problem can arise in a multiprocessor when there is no method to ensure cache coherence.  In the example given in the text, the code below is executed.&lt;br /&gt;
&lt;br /&gt;
{{{&lt;br /&gt;
sum = 0;&lt;br /&gt;
#pragma omp parallel for&lt;br /&gt;
for (i=0; i&amp;lt;2; i++) {&lt;br /&gt;
	#pragma omp critical {&lt;br /&gt;
		sum = sum + a[i];&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
print sum;&lt;br /&gt;
}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The problem that will arise as discussed in the text is that P0 will calculate a value for sum, and store it in its cache, and since P1 is not aware of the contents of P0's cache, it will read an invalid value for sum from main memory.  It will be impossible to obtain the actual value for sum since each processor now believes that it possess the correct value for sum.  That is, since they both read the value of sum from main memory to be 0, P0 thinks that the value of sum to be sum + a[0] while P1 thinks the value of sum to be sum + a[1].  It is important to note that placing the summation in a critical section does not fix this problem, since the problem is not that the 2 processors are executing at the same time, but that the main memory is not being updated and that the processors are not aware that the correct value for sum is now present (and only present) in another processors cache.&lt;br /&gt;
&lt;br /&gt;
= Memory Consistency =&lt;br /&gt;
&lt;br /&gt;
Another important issue in multiprocessor systems is the ordering of loads and stores into memory.  The Solihin text gives an example of a signal-wait synchronization.  In this example, P0 generates a certain piece of data and then signals (by setting a certain memory location to 1) that this data is now ready.  P1 is spinning in a while waiting for this data ready flag to become 1, and then it will print the data.  It is important that the complier understand what is going on so that the program order is preserved.  In C, this can be accomplished by declaring certain variables as volatile.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Uniprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a uniprocessor system, memory ordering can be changed by the compiler quite a bit to ensure the best possible performance.  The 2008 blog post on flickeringtubelight.net [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]  goes into some details about ordering on a uniprocessor vs. a multiprocessor.  For example, reordering memory operations to different addresses is fine, and will cause no harm on a uniprocessor system.  Some examples of OK changes to ordering are:&lt;br /&gt;
&lt;br /&gt;
(load A, load B) &amp;gt; (load B, load A)&lt;br /&gt;
(store B, store A) &amp;gt; (store A, store B)&lt;br /&gt;
&lt;br /&gt;
These are OK since we on a uniprocessor system we can be certain that there is not another processor waiting for this information or &amp;quot;could observe this order and infer anything from the order&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Although it appears that we can freely change the order of memory operations on a uniprocessor, even on a uniprocessor we cannot change the order of operations to the ''same'' address.  For example (load A, store A) --&amp;gt; (store A, load A) would not be OK.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Multiprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a multiprocessor much more care must be taken to ensure that all of the loads and stores are committed to memory in a valid order.  According to the blog referred to above the following must take place on a multiprocessor system:&lt;br /&gt;
&lt;br /&gt;
(store A, store B): maintained in order.&lt;br /&gt;
(load A, store B): load must be done first, ignoring a younger store in the queue.&lt;br /&gt;
(store A, load B): load must be not go ahead of the store, even though the store is to a different address.&lt;br /&gt;
(load A, load B): even if the addresses are different, the older load must go first.&lt;br /&gt;
&lt;br /&gt;
= Synchronization =&lt;br /&gt;
&lt;br /&gt;
== Open MP ==&lt;br /&gt;
The Solihin text uses the &amp;quot;#pragma omp&amp;quot; critical directive in the code given in the cache-coherence section above.  In order to use this directive the hardware must have some provision to ensure that only this one thread is going to be accessing the critical section at a given time.  According to the text, the problem not only exists on multiprocessor systems but on uniprocessors as well.  The problem discussed in the text is based on the implementation of a lock function.&lt;br /&gt;
&lt;br /&gt;
The problem is that with out special directives, there is no way to ensure that only 1 processor obtains that lock, and in turn that there is only one processing element inside the critical section.  The text suggests that the one good way to remedy this problem is to use an atomic instruction for the locking function.  With an atomic function, all commands must execute successfully or else it will appear that none of the commands were executed.  This allows for one processor to obtain the lock and enter the critical section, while the other processor(s) wait until the lock is released before entering the critical section. &lt;br /&gt;
&lt;br /&gt;
== Fence Insertion ==&lt;br /&gt;
&lt;br /&gt;
One method that is commonly used on production shared memory systems and microprocessors it the insertion of fences.  These fences can be used by the programmer to force the chip to perform a synchronization, or wait until &amp;quot;all previous memory operations of the processor are guaranteed to have completed&amp;quot; [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]  Fence insertion is a method giving the programmer (or compiler) control over the hardware's default ordering of memory operations (such as sequential consistency, processor consistency, weak ordering, etc).  It is important from a performance standpoint that the complier be able to quickly and efficiently insert fences automatically, and the algorithms used for this automatic insertion have a large bearing on performance. [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]&lt;br /&gt;
&lt;br /&gt;
=== Instructions used for fence operations ===&lt;br /&gt;
*SPARC V8 &amp;gt; store barrier&lt;br /&gt;
*SPARC V9 &amp;gt; MEMBAR&lt;br /&gt;
*Alpha &amp;gt; memory barrier and write memory barrier&lt;br /&gt;
*MIPS / PPC &amp;gt; sync&lt;br /&gt;
*Intel x86 &amp;gt; lfence (load) sfence (store)&lt;br /&gt;
&lt;br /&gt;
Taken from [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]&lt;br /&gt;
&lt;br /&gt;
== Other Methods ==&lt;br /&gt;
&lt;br /&gt;
There are many other ways to implement synchronization directives as well.  This ACM article [https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf] discusses using a test and set method for synchronization as well as a direct interrupt to another core.  As it states, both of these are special hardware solutions that must be implemented in order for the programmer to be able to take advantage of them.  The programmer (or complier) is responsible for knowing which synchronization directives are available on a given architecture and implementing them in an efficient manner.&lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
&lt;br /&gt;
* Notes on Memory Consistancy and Cache Coherence [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]&lt;br /&gt;
&lt;br /&gt;
* Mirko Loghi, Massimo Poncino, Luca Benini, Cache Coherence Tradeoffs in Shared-Memory MPSoCs [https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf]&lt;br /&gt;
&lt;br /&gt;
* Automatic fence insertion for shared memory multiprocessing [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790 http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31536</id>
		<title>CSC/ECE 506 Spring 2010/ch 7 pl/</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31536"/>
		<updated>2010-04-05T20:04:56Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: /* Fence Insertion */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Shared-memory multiprocessors run into several problems that are more pronounced than their uniprocessor counterparts.  The Solihin text used in this course goes into detail on three of these issues, that is cache coherence, memory consistency and synchronization.  It is the goal of this wiki supplement to discuss these three issues and also what can be done to ensure that instructions are handled in both a timely and efficient manner and in a manner that is consistent with what the programmer might desire.&lt;br /&gt;
&lt;br /&gt;
= Cache Coherence =&lt;br /&gt;
&lt;br /&gt;
This problem arises when each chip in the system has its own separate and discrete cache.  The Solihin text gives a good example on how a problem can arise in a multiprocessor when there is no method to ensure cache coherence.  In the example given in the text, the code below is executed.&lt;br /&gt;
&lt;br /&gt;
{{{&lt;br /&gt;
sum = 0;&lt;br /&gt;
#pragma omp parallel for&lt;br /&gt;
for (i=0; i&amp;lt;2; i++) {&lt;br /&gt;
	#pragma omp critical {&lt;br /&gt;
		sum = sum + a[i];&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
print sum;&lt;br /&gt;
}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The problem that will arise as discussed in the text is that P0 will calculate a value for sum, and store it in its cache, and since P1 is not aware of the contents of P0's cache, it will read an invalid value for sum from main memory.  It will be impossible to obtain the actual value for sum since each processor now believes that it possess the correct value for sum.  That is, since they both read the value of sum from main memory to be 0, P0 thinks that the value of sum to be sum + a[0] while P1 thinks the value of sum to be sum + a[1].  It is important to note that placing the summation in a critical section does not fix this problem, since the problem is not that the 2 processors are executing at the same time, but that the main memory is not being updated and that the processors are not aware that the correct value for sum is now present (and only present) in another processors cache.&lt;br /&gt;
&lt;br /&gt;
= Memory Consistency =&lt;br /&gt;
&lt;br /&gt;
Another important issue in multiprocessor systems is the ordering of loads and stores into memory.  The Solihin text gives an example of a signal-wait synchronization.  In this example, P0 generates a certain piece of data and then signals (by setting a certain memory location to 1) that this data is now ready.  P1 is spinning in a while waiting for this data ready flag to become 1, and then it will print the data.  It is important that the complier understand what is going on so that the program order is preserved.  In C, this can be accomplished by declaring certain variables as volatile.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Uniprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a uniprocessor system, memory ordering can be changed by the compiler quite a bit to ensure the best possible performance.  The 2008 blog post on flickeringtubelight.net [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]  goes into some details about ordering on a uniprocessor vs. a multiprocessor.  For example, reordering memory operations to different addresses is fine, and will cause no harm on a uniprocessor system.  Some examples of OK changes to ordering are:&lt;br /&gt;
&lt;br /&gt;
(load A, load B) &amp;gt; (load B, load A)&lt;br /&gt;
(store B, store A) &amp;gt; (store A, store B)&lt;br /&gt;
&lt;br /&gt;
These are OK since we on a uniprocessor system we can be certain that there is not another processor waiting for this information or &amp;quot;could observe this order and infer anything from the order&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Although it appears that we can freely change the order of memory operations on a uniprocessor, even on a uniprocessor we cannot change the order of operations to the ''same'' address.  For example (load A, store A) --&amp;gt; (store A, load A) would not be OK.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Multiprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a multiprocessor much more care must be taken to ensure that all of the loads and stores are committed to memory in a valid order.  According to the blog referred to above the following must take place on a multiprocessor system:&lt;br /&gt;
&lt;br /&gt;
(store A, store B): maintained in order.&lt;br /&gt;
(load A, store B): load must be done first, ignoring a younger store in the queue.&lt;br /&gt;
(store A, load B): load must be not go ahead of the store, even though the store is to a different address.&lt;br /&gt;
(load A, load B): even if the addresses are different, the older load must go first.&lt;br /&gt;
&lt;br /&gt;
= Synchronization =&lt;br /&gt;
&lt;br /&gt;
== Open MP ==&lt;br /&gt;
The Solihin text uses the &amp;quot;#pragma omp&amp;quot; critical directive in the code given in the cache-coherence section above.  In order to use this directive the hardware must have some provision to ensure that only this one thread is going to be accessing the critical section at a given time.  According to the text, the problem not only exists on multiprocessor systems but on uniprocessors as well.  The problem discussed in the text is based on the implementation of a lock function.&lt;br /&gt;
&lt;br /&gt;
The problem is that with out special directives, there is no way to ensure that only 1 processor obtains that lock, and in turn that there is only one processing element inside the critical section.  The text suggests that the one good way to remedy this problem is to use an atomic instruction for the locking function.  With an atomic function, all commands must execute successfully or else it will appear that none of the commands were executed.  This allows for one processor to obtain the lock and enter the critical section, while the other processor(s) wait until the lock is released before entering the critical section. &lt;br /&gt;
&lt;br /&gt;
== Fence Insertion ==&lt;br /&gt;
&lt;br /&gt;
One method that is commonly used on production shared memory systems and microprocessors it the insertion of fences.  These fences can be used by the programmer to force the chip to perform a synchronization, or wait until &amp;quot;all previous memory operations of the processor are guaranteed to have completed&amp;quot; [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]  Fence insertion is a method giving the programmer (or compiler) control over the hardware's default ordering of memory operations (such as sequential consistency, processor consistency, weak ordering, etc).  It is important from a performance standpoint that the complier be able to quickly and efficiently insert fences automatically, and the algorithms used for this automatic insertion have a large bearing on performance. [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]&lt;br /&gt;
&lt;br /&gt;
=== Instructions used for fence operations ===&lt;br /&gt;
*SPARC V8 &amp;gt; store barrier&lt;br /&gt;
*SPARC V9 &amp;gt; MEMBAR&lt;br /&gt;
*Alpha &amp;gt; memory barrier and write memory barrier&lt;br /&gt;
*MIPS / PPC &amp;gt; sync&lt;br /&gt;
*Intel x86 &amp;gt; lfence (load) sfence (store)&lt;br /&gt;
&lt;br /&gt;
Taken from [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]&lt;br /&gt;
&lt;br /&gt;
== Other Methods ==&lt;br /&gt;
&lt;br /&gt;
There are many other ways to implement synchronization directives as well.  The ACM article [https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf] discusses using a test and set method for synchronization as well as a direct interrupt to another core.  As it states, both of these are special hardware solutions that must be implemented in order for the programmer to be able to take advantage of them.  The programmer (or complier) is responsible for knowing which synchronization directives are available on a given architecture and implementing them in an efficient manner.&lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
&lt;br /&gt;
* Notes on Memory Consistancy and Cache Coherence [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]&lt;br /&gt;
&lt;br /&gt;
* Mirko Loghi, Massimo Poncino, Luca Benini, Cache Coherence Tradeoffs in Shared-Memory MPSoCs [https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf]&lt;br /&gt;
&lt;br /&gt;
* Automatic fence insertion for shared memory multiprocessing [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790 http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31535</id>
		<title>CSC/ECE 506 Spring 2010/ch 7 pl/</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31535"/>
		<updated>2010-04-05T20:01:56Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: /* Other Methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Shared-memory multiprocessors run into several problems that are more pronounced than their uniprocessor counterparts.  The Solihin text used in this course goes into detail on three of these issues, that is cache coherence, memory consistency and synchronization.  It is the goal of this wiki supplement to discuss these three issues and also what can be done to ensure that instructions are handled in both a timely and efficient manner and in a manner that is consistent with what the programmer might desire.&lt;br /&gt;
&lt;br /&gt;
= Cache Coherence =&lt;br /&gt;
&lt;br /&gt;
This problem arises when each chip in the system has its own separate and discrete cache.  The Solihin text gives a good example on how a problem can arise in a multiprocessor when there is no method to ensure cache coherence.  In the example given in the text, the code below is executed.&lt;br /&gt;
&lt;br /&gt;
{{{&lt;br /&gt;
sum = 0;&lt;br /&gt;
#pragma omp parallel for&lt;br /&gt;
for (i=0; i&amp;lt;2; i++) {&lt;br /&gt;
	#pragma omp critical {&lt;br /&gt;
		sum = sum + a[i];&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
print sum;&lt;br /&gt;
}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The problem that will arise as discussed in the text is that P0 will calculate a value for sum, and store it in its cache, and since P1 is not aware of the contents of P0's cache, it will read an invalid value for sum from main memory.  It will be impossible to obtain the actual value for sum since each processor now believes that it possess the correct value for sum.  That is, since they both read the value of sum from main memory to be 0, P0 thinks that the value of sum to be sum + a[0] while P1 thinks the value of sum to be sum + a[1].  It is important to note that placing the summation in a critical section does not fix this problem, since the problem is not that the 2 processors are executing at the same time, but that the main memory is not being updated and that the processors are not aware that the correct value for sum is now present (and only present) in another processors cache.&lt;br /&gt;
&lt;br /&gt;
= Memory Consistency =&lt;br /&gt;
&lt;br /&gt;
Another important issue in multiprocessor systems is the ordering of loads and stores into memory.  The Solihin text gives an example of a signal-wait synchronization.  In this example, P0 generates a certain piece of data and then signals (by setting a certain memory location to 1) that this data is now ready.  P1 is spinning in a while waiting for this data ready flag to become 1, and then it will print the data.  It is important that the complier understand what is going on so that the program order is preserved.  In C, this can be accomplished by declaring certain variables as volatile.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Uniprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a uniprocessor system, memory ordering can be changed by the compiler quite a bit to ensure the best possible performance.  The 2008 blog post on flickeringtubelight.net [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]  goes into some details about ordering on a uniprocessor vs. a multiprocessor.  For example, reordering memory operations to different addresses is fine, and will cause no harm on a uniprocessor system.  Some examples of OK changes to ordering are:&lt;br /&gt;
&lt;br /&gt;
(load A, load B) &amp;gt; (load B, load A)&lt;br /&gt;
(store B, store A) &amp;gt; (store A, store B)&lt;br /&gt;
&lt;br /&gt;
These are OK since we on a uniprocessor system we can be certain that there is not another processor waiting for this information or &amp;quot;could observe this order and infer anything from the order&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Although it appears that we can freely change the order of memory operations on a uniprocessor, even on a uniprocessor we cannot change the order of operations to the ''same'' address.  For example (load A, store A) --&amp;gt; (store A, load A) would not be OK.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Multiprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a multiprocessor much more care must be taken to ensure that all of the loads and stores are committed to memory in a valid order.  According to the blog referred to above the following must take place on a multiprocessor system:&lt;br /&gt;
&lt;br /&gt;
(store A, store B): maintained in order.&lt;br /&gt;
(load A, store B): load must be done first, ignoring a younger store in the queue.&lt;br /&gt;
(store A, load B): load must be not go ahead of the store, even though the store is to a different address.&lt;br /&gt;
(load A, load B): even if the addresses are different, the older load must go first.&lt;br /&gt;
&lt;br /&gt;
= Synchronization =&lt;br /&gt;
&lt;br /&gt;
== Open MP ==&lt;br /&gt;
The Solihin text uses the &amp;quot;#pragma omp&amp;quot; critical directive in the code given in the cache-coherence section above.  In order to use this directive the hardware must have some provision to ensure that only this one thread is going to be accessing the critical section at a given time.  According to the text, the problem not only exists on multiprocessor systems but on uniprocessors as well.  The problem discussed in the text is based on the implementation of a lock function.&lt;br /&gt;
&lt;br /&gt;
The problem is that with out special directives, there is no way to ensure that only 1 processor obtains that lock, and in turn that there is only one processing element inside the critical section.  The text suggests that the one good way to remedy this problem is to use an atomic instruction for the locking function.  With an atomic function, all commands must execute successfully or else it will appear that none of the commands were executed.  This allows for one processor to obtain the lock and enter the critical section, while the other processor(s) wait until the lock is released before entering the critical section. &lt;br /&gt;
&lt;br /&gt;
== Fence Insertion ==&lt;br /&gt;
&lt;br /&gt;
One method that is commonly used on production shared memory systems and microprocessors it the insertion of fences.  These fences can be used by the programmer to force the chip to perform a synchronization, or wait until &amp;quot;all previous memory operations of the processor are guaranteed to have completed&amp;quot; [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]  Fence insertion is an important go between for the programmer, allowing control over the hardware's default ordering of memory operations.  It is important from a performance standpoint that the complier be able to quickly and efficiently insert fences automatically, and the algorithms used for this automatic insertion have a large bearing on performance. [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]&lt;br /&gt;
&lt;br /&gt;
=== Instructions used for fence operations ===&lt;br /&gt;
*SPARC V8 &amp;gt; store barrier&lt;br /&gt;
*SPARC V9 &amp;gt; MEMBAR&lt;br /&gt;
*Alpha &amp;gt; memory barrier and write memory barrier&lt;br /&gt;
*MIPS / PPC &amp;gt; sync&lt;br /&gt;
*Intel x86 &amp;gt; lfence (load) sfence (store)&lt;br /&gt;
&lt;br /&gt;
Taken from [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]&lt;br /&gt;
&lt;br /&gt;
== Other Methods ==&lt;br /&gt;
&lt;br /&gt;
There are many other ways to implement synchronization directives as well.  The ACM article [https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf] discusses using a test and set method for synchronization as well as a direct interrupt to another core.  As it states, both of these are special hardware solutions that must be implemented in order for the programmer to be able to take advantage of them.  The programmer (or complier) is responsible for knowing which synchronization directives are available on a given architecture and implementing them in an efficient manner.&lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
&lt;br /&gt;
* Notes on Memory Consistancy and Cache Coherence [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]&lt;br /&gt;
&lt;br /&gt;
* Mirko Loghi, Massimo Poncino, Luca Benini, Cache Coherence Tradeoffs in Shared-Memory MPSoCs [https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf]&lt;br /&gt;
&lt;br /&gt;
* Automatic fence insertion for shared memory multiprocessing [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790 http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31534</id>
		<title>CSC/ECE 506 Spring 2010/ch 7 pl/</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31534"/>
		<updated>2010-04-05T19:59:21Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: /* Synchronization */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Shared-memory multiprocessors run into several problems that are more pronounced than their uniprocessor counterparts.  The Solihin text used in this course goes into detail on three of these issues, that is cache coherence, memory consistency and synchronization.  It is the goal of this wiki supplement to discuss these three issues and also what can be done to ensure that instructions are handled in both a timely and efficient manner and in a manner that is consistent with what the programmer might desire.&lt;br /&gt;
&lt;br /&gt;
= Cache Coherence =&lt;br /&gt;
&lt;br /&gt;
This problem arises when each chip in the system has its own separate and discrete cache.  The Solihin text gives a good example on how a problem can arise in a multiprocessor when there is no method to ensure cache coherence.  In the example given in the text, the code below is executed.&lt;br /&gt;
&lt;br /&gt;
{{{&lt;br /&gt;
sum = 0;&lt;br /&gt;
#pragma omp parallel for&lt;br /&gt;
for (i=0; i&amp;lt;2; i++) {&lt;br /&gt;
	#pragma omp critical {&lt;br /&gt;
		sum = sum + a[i];&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
print sum;&lt;br /&gt;
}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The problem that will arise as discussed in the text is that P0 will calculate a value for sum, and store it in its cache, and since P1 is not aware of the contents of P0's cache, it will read an invalid value for sum from main memory.  It will be impossible to obtain the actual value for sum since each processor now believes that it possess the correct value for sum.  That is, since they both read the value of sum from main memory to be 0, P0 thinks that the value of sum to be sum + a[0] while P1 thinks the value of sum to be sum + a[1].  It is important to note that placing the summation in a critical section does not fix this problem, since the problem is not that the 2 processors are executing at the same time, but that the main memory is not being updated and that the processors are not aware that the correct value for sum is now present (and only present) in another processors cache.&lt;br /&gt;
&lt;br /&gt;
= Memory Consistency =&lt;br /&gt;
&lt;br /&gt;
Another important issue in multiprocessor systems is the ordering of loads and stores into memory.  The Solihin text gives an example of a signal-wait synchronization.  In this example, P0 generates a certain piece of data and then signals (by setting a certain memory location to 1) that this data is now ready.  P1 is spinning in a while waiting for this data ready flag to become 1, and then it will print the data.  It is important that the complier understand what is going on so that the program order is preserved.  In C, this can be accomplished by declaring certain variables as volatile.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Uniprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a uniprocessor system, memory ordering can be changed by the compiler quite a bit to ensure the best possible performance.  The 2008 blog post on flickeringtubelight.net [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]  goes into some details about ordering on a uniprocessor vs. a multiprocessor.  For example, reordering memory operations to different addresses is fine, and will cause no harm on a uniprocessor system.  Some examples of OK changes to ordering are:&lt;br /&gt;
&lt;br /&gt;
(load A, load B) &amp;gt; (load B, load A)&lt;br /&gt;
(store B, store A) &amp;gt; (store A, store B)&lt;br /&gt;
&lt;br /&gt;
These are OK since we on a uniprocessor system we can be certain that there is not another processor waiting for this information or &amp;quot;could observe this order and infer anything from the order&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Although it appears that we can freely change the order of memory operations on a uniprocessor, even on a uniprocessor we cannot change the order of operations to the ''same'' address.  For example (load A, store A) --&amp;gt; (store A, load A) would not be OK.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Multiprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a multiprocessor much more care must be taken to ensure that all of the loads and stores are committed to memory in a valid order.  According to the blog referred to above the following must take place on a multiprocessor system:&lt;br /&gt;
&lt;br /&gt;
(store A, store B): maintained in order.&lt;br /&gt;
(load A, store B): load must be done first, ignoring a younger store in the queue.&lt;br /&gt;
(store A, load B): load must be not go ahead of the store, even though the store is to a different address.&lt;br /&gt;
(load A, load B): even if the addresses are different, the older load must go first.&lt;br /&gt;
&lt;br /&gt;
= Synchronization =&lt;br /&gt;
&lt;br /&gt;
== Open MP ==&lt;br /&gt;
The Solihin text uses the &amp;quot;#pragma omp&amp;quot; critical directive in the code given in the cache-coherence section above.  In order to use this directive the hardware must have some provision to ensure that only this one thread is going to be accessing the critical section at a given time.  According to the text, the problem not only exists on multiprocessor systems but on uniprocessors as well.  The problem discussed in the text is based on the implementation of a lock function.&lt;br /&gt;
&lt;br /&gt;
The problem is that with out special directives, there is no way to ensure that only 1 processor obtains that lock, and in turn that there is only one processing element inside the critical section.  The text suggests that the one good way to remedy this problem is to use an atomic instruction for the locking function.  With an atomic function, all commands must execute successfully or else it will appear that none of the commands were executed.  This allows for one processor to obtain the lock and enter the critical section, while the other processor(s) wait until the lock is released before entering the critical section. &lt;br /&gt;
&lt;br /&gt;
== Fence Insertion ==&lt;br /&gt;
&lt;br /&gt;
One method that is commonly used on production shared memory systems and microprocessors it the insertion of fences.  These fences can be used by the programmer to force the chip to perform a synchronization, or wait until &amp;quot;all previous memory operations of the processor are guaranteed to have completed&amp;quot; [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]  Fence insertion is an important go between for the programmer, allowing control over the hardware's default ordering of memory operations.  It is important from a performance standpoint that the complier be able to quickly and efficiently insert fences automatically, and the algorithms used for this automatic insertion have a large bearing on performance. [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]&lt;br /&gt;
&lt;br /&gt;
=== Instructions used for fence operations ===&lt;br /&gt;
*SPARC V8 &amp;gt; store barrier&lt;br /&gt;
*SPARC V9 &amp;gt; MEMBAR&lt;br /&gt;
*Alpha &amp;gt; memory barrier and write memory barrier&lt;br /&gt;
*MIPS / PPC &amp;gt; sync&lt;br /&gt;
*Intel x86 &amp;gt; lfence (load) sfence (store)&lt;br /&gt;
&lt;br /&gt;
Taken from [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]&lt;br /&gt;
&lt;br /&gt;
== Other Methods ==&lt;br /&gt;
&lt;br /&gt;
There are many other ways to implement synchronization directives as well.  The ACM article discusses using a test and set method for synchronization as well as a direct interrupt to another core.  As it states, both of these are special hardware solutions that must be implemented in order for the programmer to be able to take advantage of them.&lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
&lt;br /&gt;
* Notes on Memory Consistancy and Cache Coherence [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]&lt;br /&gt;
&lt;br /&gt;
* Mirko Loghi, Massimo Poncino, Luca Benini, Cache Coherence Tradeoffs in Shared-Memory MPSoCs [https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf]&lt;br /&gt;
&lt;br /&gt;
* Automatic fence insertion for shared memory multiprocessing [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790 http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31533</id>
		<title>CSC/ECE 506 Spring 2010/ch 7 pl/</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31533"/>
		<updated>2010-04-05T19:47:17Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: /* Ordering on a Uniprocessor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Shared-memory multiprocessors run into several problems that are more pronounced than their uniprocessor counterparts.  The Solihin text used in this course goes into detail on three of these issues, that is cache coherence, memory consistency and synchronization.  It is the goal of this wiki supplement to discuss these three issues and also what can be done to ensure that instructions are handled in both a timely and efficient manner and in a manner that is consistent with what the programmer might desire.&lt;br /&gt;
&lt;br /&gt;
= Cache Coherence =&lt;br /&gt;
&lt;br /&gt;
This problem arises when each chip in the system has its own separate and discrete cache.  The Solihin text gives a good example on how a problem can arise in a multiprocessor when there is no method to ensure cache coherence.  In the example given in the text, the code below is executed.&lt;br /&gt;
&lt;br /&gt;
{{{&lt;br /&gt;
sum = 0;&lt;br /&gt;
#pragma omp parallel for&lt;br /&gt;
for (i=0; i&amp;lt;2; i++) {&lt;br /&gt;
	#pragma omp critical {&lt;br /&gt;
		sum = sum + a[i];&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
print sum;&lt;br /&gt;
}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The problem that will arise as discussed in the text is that P0 will calculate a value for sum, and store it in its cache, and since P1 is not aware of the contents of P0's cache, it will read an invalid value for sum from main memory.  It will be impossible to obtain the actual value for sum since each processor now believes that it possess the correct value for sum.  That is, since they both read the value of sum from main memory to be 0, P0 thinks that the value of sum to be sum + a[0] while P1 thinks the value of sum to be sum + a[1].  It is important to note that placing the summation in a critical section does not fix this problem, since the problem is not that the 2 processors are executing at the same time, but that the main memory is not being updated and that the processors are not aware that the correct value for sum is now present (and only present) in another processors cache.&lt;br /&gt;
&lt;br /&gt;
= Memory Consistency =&lt;br /&gt;
&lt;br /&gt;
Another important issue in multiprocessor systems is the ordering of loads and stores into memory.  The Solihin text gives an example of a signal-wait synchronization.  In this example, P0 generates a certain piece of data and then signals (by setting a certain memory location to 1) that this data is now ready.  P1 is spinning in a while waiting for this data ready flag to become 1, and then it will print the data.  It is important that the complier understand what is going on so that the program order is preserved.  In C, this can be accomplished by declaring certain variables as volatile.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Uniprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a uniprocessor system, memory ordering can be changed by the compiler quite a bit to ensure the best possible performance.  The 2008 blog post on flickeringtubelight.net [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]  goes into some details about ordering on a uniprocessor vs. a multiprocessor.  For example, reordering memory operations to different addresses is fine, and will cause no harm on a uniprocessor system.  Some examples of OK changes to ordering are:&lt;br /&gt;
&lt;br /&gt;
(load A, load B) &amp;gt; (load B, load A)&lt;br /&gt;
(store B, store A) &amp;gt; (store A, store B)&lt;br /&gt;
&lt;br /&gt;
These are OK since we on a uniprocessor system we can be certain that there is not another processor waiting for this information or &amp;quot;could observe this order and infer anything from the order&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Although it appears that we can freely change the order of memory operations on a uniprocessor, even on a uniprocessor we cannot change the order of operations to the ''same'' address.  For example (load A, store A) --&amp;gt; (store A, load A) would not be OK.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Multiprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a multiprocessor much more care must be taken to ensure that all of the loads and stores are committed to memory in a valid order.  According to the blog referred to above the following must take place on a multiprocessor system:&lt;br /&gt;
&lt;br /&gt;
(store A, store B): maintained in order.&lt;br /&gt;
(load A, store B): load must be done first, ignoring a younger store in the queue.&lt;br /&gt;
(store A, load B): load must be not go ahead of the store, even though the store is to a different address.&lt;br /&gt;
(load A, load B): even if the addresses are different, the older load must go first.&lt;br /&gt;
&lt;br /&gt;
= Synchronization =&lt;br /&gt;
&lt;br /&gt;
The Solihin text uses the &amp;quot;#pragma omp&amp;quot; critical directive in the code given in the cache-coherence section above.  In order to use this directive the hardware must have some provision to ensure that only this one thread is going to be accessing the critical section at a given time.  According to the text, the problem not only exists on multiprocessor systems but on uniprocessors as well.  The problem discussed in the text is based on the implementation of a lock function.&lt;br /&gt;
&lt;br /&gt;
The problem is that with out special directives, there is no way to ensure that only 1 processor obtains that lock, and in turn that there is only one processing element inside the critical section.  The text suggests that the one good way to remedy this problem is to use an atomic instruction for the locking function.  With an atomic function, all commands must execute successfully or else it will appear that none of the commands were executed.  This allows for one processor to obtain the lock and enter the critical section, while the other processor(s) wait until the lock is released before entering the critical section. &lt;br /&gt;
&lt;br /&gt;
There are many other ways to implement synchronization directives as well.  The ACM article discusses using a test and set method for synchronization as well as a direct interrupt to another core.  As it states, both of these are special hardware solutions that must be implemented in order for the programmer to be able to take advantage of them. &lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
&lt;br /&gt;
* Notes on Memory Consistancy and Cache Coherence [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]&lt;br /&gt;
&lt;br /&gt;
* Mirko Loghi, Massimo Poncino, Luca Benini, Cache Coherence Tradeoffs in Shared-Memory MPSoCs [https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf]&lt;br /&gt;
&lt;br /&gt;
* Automatic fence insertion for shared memory multiprocessing [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790 http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31532</id>
		<title>CSC/ECE 506 Spring 2010/ch 7 pl/</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31532"/>
		<updated>2010-04-05T19:46:32Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: /* References */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Shared-memory multiprocessors run into several problems that are more pronounced than their uniprocessor counterparts.  The Solihin text used in this course goes into detail on three of these issues, that is cache coherence, memory consistency and synchronization.  It is the goal of this wiki supplement to discuss these three issues and also what can be done to ensure that instructions are handled in both a timely and efficient manner and in a manner that is consistent with what the programmer might desire.&lt;br /&gt;
&lt;br /&gt;
= Cache Coherence =&lt;br /&gt;
&lt;br /&gt;
This problem arises when each chip in the system has its own separate and discrete cache.  The Solihin text gives a good example on how a problem can arise in a multiprocessor when there is no method to ensure cache coherence.  In the example given in the text, the code below is executed.&lt;br /&gt;
&lt;br /&gt;
{{{&lt;br /&gt;
sum = 0;&lt;br /&gt;
#pragma omp parallel for&lt;br /&gt;
for (i=0; i&amp;lt;2; i++) {&lt;br /&gt;
	#pragma omp critical {&lt;br /&gt;
		sum = sum + a[i];&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
print sum;&lt;br /&gt;
}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The problem that will arise as discussed in the text is that P0 will calculate a value for sum, and store it in its cache, and since P1 is not aware of the contents of P0's cache, it will read an invalid value for sum from main memory.  It will be impossible to obtain the actual value for sum since each processor now believes that it possess the correct value for sum.  That is, since they both read the value of sum from main memory to be 0, P0 thinks that the value of sum to be sum + a[0] while P1 thinks the value of sum to be sum + a[1].  It is important to note that placing the summation in a critical section does not fix this problem, since the problem is not that the 2 processors are executing at the same time, but that the main memory is not being updated and that the processors are not aware that the correct value for sum is now present (and only present) in another processors cache.&lt;br /&gt;
&lt;br /&gt;
= Memory Consistency =&lt;br /&gt;
&lt;br /&gt;
Another important issue in multiprocessor systems is the ordering of loads and stores into memory.  The Solihin text gives an example of a signal-wait synchronization.  In this example, P0 generates a certain piece of data and then signals (by setting a certain memory location to 1) that this data is now ready.  P1 is spinning in a while waiting for this data ready flag to become 1, and then it will print the data.  It is important that the complier understand what is going on so that the program order is preserved.  In C, this can be accomplished by declaring certain variables as volatile.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Uniprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a uniprocessor system, memory ordering can be changed by the compiler quite a bit to ensure the best possible performance.  The 2008 blog post on flickeringtubelight.net goes into some details about ordering on a uniprocessor vs. a multiprocessor.  For example, reordering memory operations to different addresses is fine, and will cause no harm on a uniprocessor system.  Some examples of OK changes to ordering are:&lt;br /&gt;
&lt;br /&gt;
(load A, load B) &amp;gt; (load B, load A)&lt;br /&gt;
(store B, store A) &amp;gt; (store A, store B)&lt;br /&gt;
&lt;br /&gt;
These are OK since we on a uniprocessor system we can be certain that there is not another processor waiting for this information or &amp;quot;could observe this order and infer anything from the order&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Although it appears that we can freely change the order of memory operations on a uniprocessor, even on a uniprocessor we cannot change the order of operations to the ''same'' address.  For example (load A, store A) --&amp;gt; (store A, load A) would not be OK.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Multiprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a multiprocessor much more care must be taken to ensure that all of the loads and stores are committed to memory in a valid order.  According to the blog referred to above the following must take place on a multiprocessor system:&lt;br /&gt;
&lt;br /&gt;
(store A, store B): maintained in order.&lt;br /&gt;
(load A, store B): load must be done first, ignoring a younger store in the queue.&lt;br /&gt;
(store A, load B): load must be not go ahead of the store, even though the store is to a different address.&lt;br /&gt;
(load A, load B): even if the addresses are different, the older load must go first.&lt;br /&gt;
&lt;br /&gt;
= Synchronization =&lt;br /&gt;
&lt;br /&gt;
The Solihin text uses the &amp;quot;#pragma omp&amp;quot; critical directive in the code given in the cache-coherence section above.  In order to use this directive the hardware must have some provision to ensure that only this one thread is going to be accessing the critical section at a given time.  According to the text, the problem not only exists on multiprocessor systems but on uniprocessors as well.  The problem discussed in the text is based on the implementation of a lock function.&lt;br /&gt;
&lt;br /&gt;
The problem is that with out special directives, there is no way to ensure that only 1 processor obtains that lock, and in turn that there is only one processing element inside the critical section.  The text suggests that the one good way to remedy this problem is to use an atomic instruction for the locking function.  With an atomic function, all commands must execute successfully or else it will appear that none of the commands were executed.  This allows for one processor to obtain the lock and enter the critical section, while the other processor(s) wait until the lock is released before entering the critical section. &lt;br /&gt;
&lt;br /&gt;
There are many other ways to implement synchronization directives as well.  The ACM article discusses using a test and set method for synchronization as well as a direct interrupt to another core.  As it states, both of these are special hardware solutions that must be implemented in order for the programmer to be able to take advantage of them. &lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
&lt;br /&gt;
* Notes on Memory Consistancy and Cache Coherence [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]&lt;br /&gt;
&lt;br /&gt;
* Mirko Loghi, Massimo Poncino, Luca Benini, Cache Coherence Tradeoffs in Shared-Memory MPSoCs [https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf]&lt;br /&gt;
&lt;br /&gt;
* Automatic fence insertion for shared memory multiprocessing [http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790 http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31531</id>
		<title>CSC/ECE 506 Spring 2010/ch 7 pl/</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31531"/>
		<updated>2010-04-05T19:45:24Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: /* References */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Shared-memory multiprocessors run into several problems that are more pronounced than their uniprocessor counterparts.  The Solihin text used in this course goes into detail on three of these issues, that is cache coherence, memory consistency and synchronization.  It is the goal of this wiki supplement to discuss these three issues and also what can be done to ensure that instructions are handled in both a timely and efficient manner and in a manner that is consistent with what the programmer might desire.&lt;br /&gt;
&lt;br /&gt;
= Cache Coherence =&lt;br /&gt;
&lt;br /&gt;
This problem arises when each chip in the system has its own separate and discrete cache.  The Solihin text gives a good example on how a problem can arise in a multiprocessor when there is no method to ensure cache coherence.  In the example given in the text, the code below is executed.&lt;br /&gt;
&lt;br /&gt;
{{{&lt;br /&gt;
sum = 0;&lt;br /&gt;
#pragma omp parallel for&lt;br /&gt;
for (i=0; i&amp;lt;2; i++) {&lt;br /&gt;
	#pragma omp critical {&lt;br /&gt;
		sum = sum + a[i];&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
print sum;&lt;br /&gt;
}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The problem that will arise as discussed in the text is that P0 will calculate a value for sum, and store it in its cache, and since P1 is not aware of the contents of P0's cache, it will read an invalid value for sum from main memory.  It will be impossible to obtain the actual value for sum since each processor now believes that it possess the correct value for sum.  That is, since they both read the value of sum from main memory to be 0, P0 thinks that the value of sum to be sum + a[0] while P1 thinks the value of sum to be sum + a[1].  It is important to note that placing the summation in a critical section does not fix this problem, since the problem is not that the 2 processors are executing at the same time, but that the main memory is not being updated and that the processors are not aware that the correct value for sum is now present (and only present) in another processors cache.&lt;br /&gt;
&lt;br /&gt;
= Memory Consistency =&lt;br /&gt;
&lt;br /&gt;
Another important issue in multiprocessor systems is the ordering of loads and stores into memory.  The Solihin text gives an example of a signal-wait synchronization.  In this example, P0 generates a certain piece of data and then signals (by setting a certain memory location to 1) that this data is now ready.  P1 is spinning in a while waiting for this data ready flag to become 1, and then it will print the data.  It is important that the complier understand what is going on so that the program order is preserved.  In C, this can be accomplished by declaring certain variables as volatile.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Uniprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a uniprocessor system, memory ordering can be changed by the compiler quite a bit to ensure the best possible performance.  The 2008 blog post on flickeringtubelight.net goes into some details about ordering on a uniprocessor vs. a multiprocessor.  For example, reordering memory operations to different addresses is fine, and will cause no harm on a uniprocessor system.  Some examples of OK changes to ordering are:&lt;br /&gt;
&lt;br /&gt;
(load A, load B) &amp;gt; (load B, load A)&lt;br /&gt;
(store B, store A) &amp;gt; (store A, store B)&lt;br /&gt;
&lt;br /&gt;
These are OK since we on a uniprocessor system we can be certain that there is not another processor waiting for this information or &amp;quot;could observe this order and infer anything from the order&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Although it appears that we can freely change the order of memory operations on a uniprocessor, even on a uniprocessor we cannot change the order of operations to the ''same'' address.  For example (load A, store A) --&amp;gt; (store A, load A) would not be OK.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Multiprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a multiprocessor much more care must be taken to ensure that all of the loads and stores are committed to memory in a valid order.  According to the blog referred to above the following must take place on a multiprocessor system:&lt;br /&gt;
&lt;br /&gt;
(store A, store B): maintained in order.&lt;br /&gt;
(load A, store B): load must be done first, ignoring a younger store in the queue.&lt;br /&gt;
(store A, load B): load must be not go ahead of the store, even though the store is to a different address.&lt;br /&gt;
(load A, load B): even if the addresses are different, the older load must go first.&lt;br /&gt;
&lt;br /&gt;
= Synchronization =&lt;br /&gt;
&lt;br /&gt;
The Solihin text uses the &amp;quot;#pragma omp&amp;quot; critical directive in the code given in the cache-coherence section above.  In order to use this directive the hardware must have some provision to ensure that only this one thread is going to be accessing the critical section at a given time.  According to the text, the problem not only exists on multiprocessor systems but on uniprocessors as well.  The problem discussed in the text is based on the implementation of a lock function.&lt;br /&gt;
&lt;br /&gt;
The problem is that with out special directives, there is no way to ensure that only 1 processor obtains that lock, and in turn that there is only one processing element inside the critical section.  The text suggests that the one good way to remedy this problem is to use an atomic instruction for the locking function.  With an atomic function, all commands must execute successfully or else it will appear that none of the commands were executed.  This allows for one processor to obtain the lock and enter the critical section, while the other processor(s) wait until the lock is released before entering the critical section. &lt;br /&gt;
&lt;br /&gt;
There are many other ways to implement synchronization directives as well.  The ACM article discusses using a test and set method for synchronization as well as a direct interrupt to another core.  As it states, both of these are special hardware solutions that must be implemented in order for the programmer to be able to take advantage of them. &lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
&lt;br /&gt;
* Notes on Memory Consistancy and Cache Coherence [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]&lt;br /&gt;
&lt;br /&gt;
* Mirko Loghi, Massimo Poncino, Luca Benini, Cache Coherence Tradeoffs in Shared-Memory MPSoCs [https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf]&lt;br /&gt;
&lt;br /&gt;
* Automatic fence insertion for shared memory multiprocessing&lt;br /&gt;
[http://portal.acm.org/citation.cfm?id=782854&amp;amp;dl=GUIDE&amp;amp;coll=GUIDE&amp;amp;CFID=84866326&amp;amp;CFTOKEN=84791790]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31247</id>
		<title>CSC/ECE 506 Spring 2010/ch 7 pl/</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_7_pl/&amp;diff=31247"/>
		<updated>2010-03-26T00:15:49Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Shared Memory multiprocessors run into several problems that are more pronounced then on their uniprocessors counterparts.  The Solihin text used in this course goes into a small amount of detail on three of these issues, that is Cache Coherence, Memory Consistency and Synchronization.  It is the goal of this wiki to discuss these three issues and also what can be done to ensure that instructions are handled in both a timely and efficient manner and in a manner that is consistent with what the programmer might desire.&lt;br /&gt;
&lt;br /&gt;
= Cache Coherence =&lt;br /&gt;
&lt;br /&gt;
This problem arises when each chip in the system has it's own separate and discrete cache.  The Solihin text gives a good example on how a problem can arise in a multiprocessor when there is no method to ensure cache coherence.  In the example given in the text, the code below is executed.&lt;br /&gt;
&lt;br /&gt;
{{{&lt;br /&gt;
sum = 0;&lt;br /&gt;
#pragma omp parallel for&lt;br /&gt;
for (i=0; i&amp;lt;2; i++) {&lt;br /&gt;
	#pragma omp critical {&lt;br /&gt;
		sum = sum + a[i];&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
print sum;&lt;br /&gt;
}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The problem that will arise as discussed in the text is that P0 will calculate a value for sum, and store it in it's cache, and since P1 is not aware of the contents of P0's cache, it will read an invalid value for sum from main memory.  It will be impossible to obtain the actual value for sum since each processor now believes that it possess the correct value for sum.  That is, since they both read the value of sum from main memory to be 0, P0 thinks that the value of sum to be sum + a[0] while P1 thinks the value of sum to be sum + a[1].  It is important to note that placing the summation in a critical section does not fix this problem, since the problem is not that the 2 processors are executing at the same time, but that the main memory is not being updated and that the processors are not aware that the correct value for sum is now present (and only present) in another processors cache.&lt;br /&gt;
&lt;br /&gt;
= Memory Consistency =&lt;br /&gt;
&lt;br /&gt;
Another important issue in multiprocessor systems is the ordering of loads and stores into memory.  The Solihin text gives an example of a signal-wait synchronization.  In this example, P0 generates a certain piece of data and then signals (by setting a certain memory location to 1) that this data is now ready.  P1 is spinning in a while waiting for this data ready flag to become 1, and then it will print the data.  It is important that the complier understand what is going on so that the program order is preserved.  In C, this can be accomplished by declaring certain variables as volatile.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Uniprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a uniprocessor system, memory ordering can be changed by the compiler quite a bit to ensure the best possible performance.  The 2008 blog post on flickeringtubelight.net goes into some details about ordering on a uniprocessor vs. a multiprocessor.  For example, reordering memory operations to different addresses is fine, and will cause no harm on a uniprocessor system.  Some examples of OK changes to ordering are:&lt;br /&gt;
&lt;br /&gt;
(load A, load B) &amp;gt; (load B, load A)&lt;br /&gt;
(store B, store A) &amp;gt; (store A, store B)&lt;br /&gt;
&lt;br /&gt;
These are OK since we on a uniprocessor system we can be certain that there is not another processor waiting for this information or &amp;quot;could observe this order and infer anything from the order&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Although it appears that we can freely change the order of memory operations on a uniprocessor, even on a uniprocessor we cannot change the order of operations to the SAME address.  For example (load A, store A) &amp;gt; (store A, load A) would not be OK.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Multiprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a multiprocessor much more care must be taken to ensure that all of the loads and stores are committed to memory in a valid order.  According to the blog referred to above the following must take place on a multiprocessor system:&lt;br /&gt;
&lt;br /&gt;
(store A, store B): maintained in order.&lt;br /&gt;
(load A, store B): load must be done first, ignoring a younger store in the queue.&lt;br /&gt;
(store A, load B): load must be not go ahead of the store, even though the store is to a different address.&lt;br /&gt;
(load A, load B): even if the addresses are different, the older load must go first.&lt;br /&gt;
&lt;br /&gt;
= Synchronization =&lt;br /&gt;
&lt;br /&gt;
The Solihin text uses the #pragma omp critical directive in the code given in the cache coherency section above.  In order to use this directive the hardware must have some provision to ensure that only this one thread is going to be accessing the critical section at a given time.  According to the text, the problem not only exists on multiprocessor systems but on uniprocessors as well.  The problem discussed in the text is based on the implementation of a lock function.&lt;br /&gt;
&lt;br /&gt;
The problem is that with out special directives, there is no way to ensure that only 1 processor obtains that lock, and in turn that there is only one processing element inside the critical section.  The text suggests that the one good way to remedy this problem is to use an atomic instruction for the locking function.  With an atomic function, all commands must execute successfully or else it will appear that none of the commands were executed.  This allows for one processor to obtain the lock and enter the critical section, while the other processor(s) wait until the lock is released before entering the critical section. &lt;br /&gt;
&lt;br /&gt;
There are many other ways to implement synchronization directives as well.  The ACM article discusses using a test and set method for synchronization as well as a direct interrupt to another core.  As it states, both of these are special hardware solutions that must be implemented in order for the programmer to be able to take advantage of them. &lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
&lt;br /&gt;
* Notes on Memory Consistancy and Cache Coherence [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]&lt;br /&gt;
&lt;br /&gt;
* Mirko Loghi, Massimo Poncino, Luca Benini, Cache Coherence Tradeoffs in Shared-Memory MPSoCs [https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_4_pl/&amp;diff=31246</id>
		<title>CSC/ECE 506 Spring 2010/ch 4 pl/</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_4_pl/&amp;diff=31246"/>
		<updated>2010-03-26T00:15:38Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_4_pl/&amp;diff=31245</id>
		<title>CSC/ECE 506 Spring 2010/ch 4 pl/</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_4_pl/&amp;diff=31245"/>
		<updated>2010-03-26T00:13:50Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Shared Memory multiprocessors run into several problems that are more pronounced then on their uniprocessors counterparts.  The Solihin text used in this course goes into a small amount of detail on three of these issues, that is Cache Coherence, Memory Consistency and Synchronization.  It is the goal of this wiki to discuss these three issues and also what can be done to ensure that instructions are handled in both a timely and efficient manner and in a manner that is consistent with what the programmer might desire.&lt;br /&gt;
&lt;br /&gt;
= Cache Coherence =&lt;br /&gt;
&lt;br /&gt;
This problem arises when each chip in the system has it's own separate and discrete cache.  The Solihin text gives a good example on how a problem can arise in a multiprocessor when there is no method to ensure cache coherence.  In the example given in the text, the code below is executed.&lt;br /&gt;
&lt;br /&gt;
{{{&lt;br /&gt;
sum = 0;&lt;br /&gt;
#pragma omp parallel for&lt;br /&gt;
for (i=0; i&amp;lt;2; i++) {&lt;br /&gt;
	#pragma omp critical {&lt;br /&gt;
		sum = sum + a[i];&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
print sum;&lt;br /&gt;
}}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The problem that will arise as discussed in the text is that P0 will calculate a value for sum, and store it in it's cache, and since P1 is not aware of the contents of P0's cache, it will read an invalid value for sum from main memory.  It will be impossible to obtain the actual value for sum since each processor now believes that it possess the correct value for sum.  That is, since they both read the value of sum from main memory to be 0, P0 thinks that the value of sum to be sum + a[0] while P1 thinks the value of sum to be sum + a[1].  It is important to note that placing the summation in a critical section does not fix this problem, since the problem is not that the 2 processors are executing at the same time, but that the main memory is not being updated and that the processors are not aware that the correct value for sum is now present (and only present) in another processors cache.&lt;br /&gt;
&lt;br /&gt;
= Memory Consistency =&lt;br /&gt;
&lt;br /&gt;
Another important issue in multiprocessor systems is the ordering of loads and stores into memory.  The Solihin text gives an example of a signal-wait synchronization.  In this example, P0 generates a certain piece of data and then signals (by setting a certain memory location to 1) that this data is now ready.  P1 is spinning in a while waiting for this data ready flag to become 1, and then it will print the data.  It is important that the complier understand what is going on so that the program order is preserved.  In C, this can be accomplished by declaring certain variables as volatile.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Uniprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a uniprocessor system, memory ordering can be changed by the compiler quite a bit to ensure the best possible performance.  The 2008 blog post on flickeringtubelight.net goes into some details about ordering on a uniprocessor vs. a multiprocessor.  For example, reordering memory operations to different addresses is fine, and will cause no harm on a uniprocessor system.  Some examples of OK changes to ordering are:&lt;br /&gt;
&lt;br /&gt;
(load A, load B) &amp;gt; (load B, load A)&lt;br /&gt;
(store B, store A) &amp;gt; (store A, store B)&lt;br /&gt;
&lt;br /&gt;
These are OK since we on a uniprocessor system we can be certain that there is not another processor waiting for this information or &amp;quot;could observe this order and infer anything from the order&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Although it appears that we can freely change the order of memory operations on a uniprocessor, even on a uniprocessor we cannot change the order of operations to the SAME address.  For example (load A, store A) &amp;gt; (store A, load A) would not be OK.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Multiprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a multiprocessor much more care must be taken to ensure that all of the loads and stores are committed to memory in a valid order.  According to the blog referred to above the following must take place on a multiprocessor system:&lt;br /&gt;
&lt;br /&gt;
(store A, store B): maintained in order.&lt;br /&gt;
(load A, store B): load must be done first, ignoring a younger store in the queue.&lt;br /&gt;
(store A, load B): load must be not go ahead of the store, even though the store is to a different address.&lt;br /&gt;
(load A, load B): even if the addresses are different, the older load must go first.&lt;br /&gt;
&lt;br /&gt;
= Synchronization =&lt;br /&gt;
&lt;br /&gt;
The Solihin text uses the #pragma omp critical directive in the code given in the cache coherency section above.  In order to use this directive the hardware must have some provision to ensure that only this one thread is going to be accessing the critical section at a given time.  According to the text, the problem not only exists on multiprocessor systems but on uniprocessors as well.  The problem discussed in the text is based on the implementation of a lock function.&lt;br /&gt;
&lt;br /&gt;
The problem is that with out special directives, there is no way to ensure that only 1 processor obtains that lock, and in turn that there is only one processing element inside the critical section.  The text suggests that the one good way to remedy this problem is to use an atomic instruction for the locking function.  With an atomic function, all commands must execute successfully or else it will appear that none of the commands were executed.  This allows for one processor to obtain the lock and enter the critical section, while the other processor(s) wait until the lock is released before entering the critical section. &lt;br /&gt;
&lt;br /&gt;
There are many other ways to implement synchronization directives as well.  The ACM article discusses using a test and set method for synchronization as well as a direct interrupt to another core.  As it states, both of these are special hardware solutions that must be implemented in order for the programmer to be able to take advantage of them. &lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
&lt;br /&gt;
* Notes on Memory Consistancy and Cache Coherence [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]&lt;br /&gt;
&lt;br /&gt;
* Mirko Loghi, Massimo Poncino, Luca Benini, Cache Coherence Tradeoffs in Shared-Memory MPSoCs [https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_4_pl/&amp;diff=31244</id>
		<title>CSC/ECE 506 Spring 2010/ch 4 pl/</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_4_pl/&amp;diff=31244"/>
		<updated>2010-03-26T00:01:46Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Shared Memory multiprocessors run into several problems that are more pronounced then on their uniprocessors counterparts.  The Solihin text used in this course goes into a small amount of detail on three of these issues, that is Cache Coherence, Memory Consistency and Synchronization.  It is the goal of this wiki to discuss these three issues and also what can be done to ensure that instructions are handled in both a timely and efficient manner and in a manner that is consistent with what the programmer might desire.&lt;br /&gt;
&lt;br /&gt;
= Cache Coherence =&lt;br /&gt;
&lt;br /&gt;
This problem arises when each chip in the system has it's own separate and discrete cache.  The Solihin text gives a good example on how a problem can arise in a multiprocessor when there is no method to ensure cache coherence.  In the example given in the text, the code below is executed.&lt;br /&gt;
&lt;br /&gt;
[code]&lt;br /&gt;
sum = 0;&lt;br /&gt;
#pragma omp parallel for&lt;br /&gt;
for (i=0; i&amp;lt;2; i++) {&lt;br /&gt;
	#pragma omp critical {&lt;br /&gt;
		sum = sum + a[i];&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
print sum;&lt;br /&gt;
[/code]&lt;br /&gt;
&lt;br /&gt;
The problem that will arise as discussed in the text is that P0 will calculate a value for sum, and store it in it's cache, and since P1 is not aware of the contents of P0's cache, it will read an invalid value for sum from main memory.  It will be impossible to obtain the actual value for sum since each processor now believes that it possess the correct value for sum.  That is, since they both read the value of sum from main memory to be 0, P0 thinks that the value of sum to be sum + a[0] while P1 thinks the value of sum to be sum + a[1].  It is important to note that placing the summation in a critical section does not fix this problem, since the problem is not that the 2 processors are executing at the same time, but that the main memory is not being updated and that the processors are not aware that the correct value for sum is now present (and only present) in another processors cache.&lt;br /&gt;
&lt;br /&gt;
= Memory Consistency =&lt;br /&gt;
&lt;br /&gt;
Another important issue in multiprocessor systems is the ordering of loads and stores into memory.  The Solihin text gives an example of a signal-wait synchronization.  In this example, P0 generates a certain piece of data and then signals (by setting a certain memory location to 1) that this data is now ready.  P1 is spinning in a while waiting for this data ready flag to become 1, and then it will print the data.  It is important that the complier understand what is going on so that the program order is preserved.  In C, this can be accomplished by declaring certain variables as volatile.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Uniprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a uniprocessor system, memory ordering can be changed by the compiler quite a bit to ensure the best possible performance.  The 2008 blog post on flickeringtubelight.net goes into some details about ordering on a uniprocessor vs. a multiprocessor.  For example, reordering memory operations to different addresses is fine, and will cause no harm on a uniprocessor system.  Some examples of OK changes to ordering are:&lt;br /&gt;
&lt;br /&gt;
(load A, load B) &amp;gt; (load B, load A)&lt;br /&gt;
(store B, store A) &amp;gt; (store A, store B)&lt;br /&gt;
&lt;br /&gt;
These are OK since we on a uniprocessor system we can be certain that there is not another processor waiting for this information or &amp;quot;could observe this order and infer anything from the order&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Although it appears that we can freely change the order of memory operations on a uniprocessor, even on a uniprocessor we cannot change the order of operations to the SAME address.  For example (load A, store A) &amp;gt; (store A, load A) would not be OK.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Multiprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a multiprocessor much more care must be taken to ensure that all of the loads and stores are committed to memory in a valid order.  According to the blog referred to above the following must take place on a multiprocessor system:&lt;br /&gt;
&lt;br /&gt;
(store A, store B): maintained in order.&lt;br /&gt;
(load A, store B): load must be done first, ignoring a younger store in the queue.&lt;br /&gt;
(store A, load B): load must be not go ahead of the store, even though the store is to a different address.&lt;br /&gt;
(load A, load B): even if the addresses are different, the older load must go first.&lt;br /&gt;
&lt;br /&gt;
= Synchronization =&lt;br /&gt;
&lt;br /&gt;
The Solihin text uses the #pragma omp critical directive in the code given in the cache coherency section above.  In order to use this directive the hardware must have some provision to ensure that only this one thread is going to be accessing the critical section at a given time.  According to the text, the problem not only exists on multiprocessor systems but on uniprocessors as well.  The problem discussed in the text is based on the implementation of a lock function.&lt;br /&gt;
&lt;br /&gt;
The problem is that with out special directives, there is no way to ensure that only 1 processor obtains that lock, and in turn that there is only one processing element inside the critical section.  The text suggests that the one good way to remedy this problem is to use an atomic instruction for the locking function.  With an atomic function, all commands must execute successfully or else it will appear that none of the commands were executed.  This allows for one processor to obtain the lock and enter the critical section, while the other processor(s) wait until the lock is released before entering the critical section. &lt;br /&gt;
&lt;br /&gt;
There are many other ways to implement synchronization directives as well.  The ACM article discusses using a test and set method for synchronization as well as a direct interrupt to another core.  As it states, both of these are special hardware solutions that must be implemented in order for the programmer to be able to take advantage of them. &lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
&lt;br /&gt;
* Notes on Memory Consistancy and Cache Coherence [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]&lt;br /&gt;
&lt;br /&gt;
* Mirko Loghi, Massimo Poncino, Luca Benini, Cache Coherence Tradeoffs in Shared-Memory MPSoCs [https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_4_pl/&amp;diff=31243</id>
		<title>CSC/ECE 506 Spring 2010/ch 4 pl/</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_506_Spring_2010/ch_4_pl/&amp;diff=31243"/>
		<updated>2010-03-26T00:01:00Z</updated>

		<summary type="html">&lt;p&gt;Pwlane: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Shared Memory multiprocessors run into several problems that are more pronounced then on their uniprocessors counterparts.  The Solihin text used in this course goes into a small amount of detail on three of these issues, that is Cache Coherence, Memory Consistency and Synchronization.  It is the goal of this wiki to discuss these three issues and also what can be done to ensure that instructions are handled in both a timely and efficient manner and in a manner that is consistent with what the programmer might desire.&lt;br /&gt;
&lt;br /&gt;
= Cache Coherence =&lt;br /&gt;
&lt;br /&gt;
This problem arises when each chip in the system has it's own separate and discrete cache.  The Solihin text gives a good example on how a problem can arise in a multiprocessor when there is no method to ensure cache coherence.  In the example given in the text, the code below is executed.&lt;br /&gt;
&lt;br /&gt;
sum = 0;&lt;br /&gt;
#pragma omp parallel for&lt;br /&gt;
for (i=0; i&amp;lt;2; i++) {&lt;br /&gt;
	#pragma omp critical {&lt;br /&gt;
		sum = sum + a[i];&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
print sum;&lt;br /&gt;
&lt;br /&gt;
The problem that will arise as discussed in the text is that P0 will calculate a value for sum, and store it in it's cache, and since P1 is not aware of the contents of P0's cache, it will read an invalid value for sum from main memory.  It will be impossible to obtain the actual value for sum since each processor now believes that it possess the correct value for sum.  That is, since they both read the value of sum from main memory to be 0, P0 thinks that the value of sum to be sum + a[0] while P1 thinks the value of sum to be sum + a[1].  It is important to note that placing the summation in a critical section does not fix this problem, since the problem is not that the 2 processors are executing at the same time, but that the main memory is not being updated and that the processors are not aware that the correct value for sum is now present (and only present) in another processors cache.&lt;br /&gt;
&lt;br /&gt;
= Memory Consistency =&lt;br /&gt;
&lt;br /&gt;
Another important issue in multiprocessor systems is the ordering of loads and stores into memory.  The Solihin text gives an example of a signal-wait synchronization.  In this example, P0 generates a certain piece of data and then signals (by setting a certain memory location to 1) that this data is now ready.  P1 is spinning in a while waiting for this data ready flag to become 1, and then it will print the data.  It is important that the complier understand what is going on so that the program order is preserved.  In C, this can be accomplished by declaring certain variables as volatile.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Uniprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a uniprocessor system, memory ordering can be changed by the compiler quite a bit to ensure the best possible performance.  The 2008 blog post on flickeringtubelight.net goes into some details about ordering on a uniprocessor vs. a multiprocessor.  For example, reordering memory operations to different addresses is fine, and will cause no harm on a uniprocessor system.  Some examples of OK changes to ordering are:&lt;br /&gt;
&lt;br /&gt;
(load A, load B) &amp;gt; (load B, load A)&lt;br /&gt;
(store B, store A) &amp;gt; (store A, store B)&lt;br /&gt;
&lt;br /&gt;
These are OK since we on a uniprocessor system we can be certain that there is not another processor waiting for this information or &amp;quot;could observe this order and infer anything from the order&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Although it appears that we can freely change the order of memory operations on a uniprocessor, even on a uniprocessor we cannot change the order of operations to the SAME address.  For example (load A, store A) &amp;gt; (store A, load A) would not be OK.&lt;br /&gt;
&lt;br /&gt;
== Ordering on a Multiprocessor ==&lt;br /&gt;
&lt;br /&gt;
On a multiprocessor much more care must be taken to ensure that all of the loads and stores are committed to memory in a valid order.  According to the blog referred to above the following must take place on a multiprocessor system:&lt;br /&gt;
&lt;br /&gt;
(store A, store B): maintained in order.&lt;br /&gt;
(load A, store B): load must be done first, ignoring a younger store in the queue.&lt;br /&gt;
(store A, load B): load must be not go ahead of the store, even though the store is to a different address.&lt;br /&gt;
(load A, load B): even if the addresses are different, the older load must go first.&lt;br /&gt;
&lt;br /&gt;
= Synchronization =&lt;br /&gt;
&lt;br /&gt;
The Solihin text uses the #pragma omp critical directive in the code given in the cache coherency section above.  In order to use this directive the hardware must have some provision to ensure that only this one thread is going to be accessing the critical section at a given time.  According to the text, the problem not only exists on multiprocessor systems but on uniprocessors as well.  The problem discussed in the text is based on the implementation of a lock function.&lt;br /&gt;
&lt;br /&gt;
The problem is that with out special directives, there is no way to ensure that only 1 processor obtains that lock, and in turn that there is only one processing element inside the critical section.  The text suggests that the one good way to remedy this problem is to use an atomic instruction for the locking function.  With an atomic function, all commands must execute successfully or else it will appear that none of the commands were executed.  This allows for one processor to obtain the lock and enter the critical section, while the other processor(s) wait until the lock is released before entering the critical section. &lt;br /&gt;
&lt;br /&gt;
There are many other ways to implement synchronization directives as well.  The ACM article discusses using a test and set method for synchronization as well as a direct interrupt to another core.  As it states, both of these are special hardware solutions that must be implemented in order for the programmer to be able to take advantage of them. &lt;br /&gt;
&lt;br /&gt;
= References = &lt;br /&gt;
* Yan Solihin, Fundamentals of Parallel Computer Architecture: Multichip and Multicore Systems, Solihin Books, August 2009.&lt;br /&gt;
&lt;br /&gt;
* Notes on Memory Consistancy and Cache Coherence [http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf http://flickeringtubelight.net/blog/wp-content/uploads/2008/06/notesonconsistencyandcoherence.pdf]&lt;br /&gt;
&lt;br /&gt;
* Mirko Loghi, Massimo Poncino, Luca Benini, Cache Coherence Tradeoffs in Shared-Memory MPSoCs [https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf https://wiki.ittc.ku.edu/ittc/images/0/0f/Loghi.pdf]&lt;/div&gt;</summary>
		<author><name>Pwlane</name></author>
	</entry>
</feed>