CSC/ECE 506 Spring 2014/3a ns: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
(Created page with "<!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="UTF-8" /> <title>CSC/ECE 506 Spring 2013/3a bs - PG_Wiki</title> <meta name="generator" content="MediaWiki 1.17.0...")
 
No edit summary
 
(136 intermediate revisions by 3 users not shown)
Line 1: Line 1:
<!DOCTYPE html>
[https://docs.google.com/a/ncsu.edu/document/d/1xRhg9ugStpe6yk5BUtJSrC41mWyMHCSteskhw205X2g/edit# Problem Statement 3a ]
<html lang="en" dir="ltr">
 
<head>
[http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_506_Spring_2013/3a_bs Previous Work ]
<meta charset="UTF-8" />
 
<title>CSC/ECE 506 Spring 2013/3a bs - PG_Wiki</title>
[http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_506_Spring_2014/3a_ns Current Work]
<meta name="generator" content="MediaWiki 1.17.0" />
 
<link rel="alternate" type="application/x-wiki" title="Edit" href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit" />
== Overview ==
<link rel="edit" title="Edit" href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit" />
 
<link rel="shortcut icon" href="/favicon.ico" />
The aim of this wiki is to highlight the synchronization mechanisms for DOALL, DOACROSS and DOPIPE parallelization techniques.
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch_desc.php" title="PG_Wiki (en)" />
 
<link rel="EditURI" type="application/rsd+xml" href="http://wiki.expertiza.ncsu.edu/api.php?action=rsd" />
== Synchronization ==
<link rel="alternate" type="application/atom+xml" title="PG_Wiki Atom feed" href="/index.php?title=Special:RecentChanges&amp;feed=atom" />
 
<link rel="stylesheet" href="/load.php?debug=false&amp;lang=en&amp;modules=mediawiki.legacy.commonPrint%2Cshared%7Cskins.vector&amp;only=styles&amp;skin=vector&amp;*" />
=== Necessity ===
<meta name="ResourceLoaderDynamicStyles" content="" />
-----------------------
<!--[if lt IE 7]><style type="text/css">body{behavior:url("/skins/vector/csshover.min.htc")}</style><![endif]--></head>
 
<body class="mediawiki ltr ns-0 ns-subject page-CSC_ECE_506_Spring_2013_3a_bs skin-vector">
When using any parallel programming model, [http://en.wikipedia.org/wiki/Synchronization_(computer_science) synchronization]<ref>Rahman, M.M.; , "Process synchronization in multiprocessor and multi-core processor," Informatics, Electronics & Vision (ICIEV), 2012 International Conference on , vol., no., pp.554-559, 18-19 May 2012</ref> is needed to guarantee accuracy of the overall program. The following situations highlight the necessity of synchronization<ref>http://people.csail.mit.edu/rinard/paper/cpande99.pdf</ref>.
<div id="mw-page-base" class="noprint"></div>
 
<div id="mw-head-base" class="noprint"></div>
Case 1:  A scenario in which the code following a parallelized loop requires that all of the parallel [http://en.wikipedia.org/wiki/Process_(computer_science)  processes] be completed before advancing.
<!-- content -->
 
<div id="content">
Case 2: A scenario in which a code segment in the middle of a parallelized section needs to be executed sequentially (critical section), to ensure program correctness.
<a id="top"></a>
 
<div id="mw-js-message" style="display:none;"></div>
Case 3: A scenario in which multiple processes must update a global variable in such a way that one process does not overwrite the updates of a different process.
<!-- firstHeading -->
 
<h1 id="firstHeading" class="firstHeading">CSC/ECE 506 Spring 2013/3a bs</h1>
=== Synchronization Mechanisms ===
<!-- /firstHeading -->
-----------------------
<!-- bodyContent -->
Let us now briefly understand the various [http://en.wikipedia.org/wiki/Synchronization_(computer_science)#Thread_or_process_synchronization process/thread synchronization mechanisms] that helps in achieving correct program execution order.
<div id="bodyContent">
 
<!-- tagline -->
'''Semaphore''': [https://en.wikipedia.org/wiki/Semaphore_(programming) Semaphore] is a variable that helps in controlling the access to a common resource in a parallel programming model. Not only do they arbitrate, but also help in avoiding race conditions. Semaphores keep only the count of the resource availability.
<div id="siteSub">From PG_Wiki</div>
 
<!-- /tagline -->
'''Mutex / Lock''': [https://en.wikipedia.org/wiki/Mutex Mutex] refers to Mutual Exclusion. It helps avoiding concurrency issues like race conditions by ensuring that no two concurrently executed processes access a critical section at the same time. Though Mutexes are essentially the same as Semaphores, the fundamental differences between them are as follows  [http://en.wikipedia.org/wiki/Semaphore_(programming)#Semaphores_vs._mutexes]:
<!-- subtitle -->
 
<div id="contentSub"></div>
1. Mutexes allow exclusive process access to a resource. Semaphores allow any process to access a resource. Thus the element of ownership in mutex ensures that only the process that has locked the mutex can unlock it. However, in case of Semaphores, the process locking and unlocking the semaphore can be different.
<!-- /subtitle -->
 
<!-- jumpto -->
2.  Mutexes support priority inversion, helping promote the current priority of the process that has the lock, in case a higher priority process starts waiting on the locked mutex.  
<div id="jump-to-nav">
 
Jump to: <a href="#mw-head">navigation</a>,
3. Mutexes, unlike Semaphores ensure that the process holding the mutex cannot be accidentally deleted by other processes.
<a href="#p-search">search</a>
 
</div>
'''Conditional Variables''': Though the use of Mutex protects an operation, it doesn’t permit the thread to wait until another thread completes an arbitrary activity (e.g. Parent thread might want to wait until the child thread has completed its execution) [http://www.cs.nmsu.edu/~jcook/Tools/pthreads/pthread_cond.html]. By giving this facility, conditional variables help in solving various synchronization problems like the producer/consumer problem [http://pages.cs.wisc.edu/~remzi/OSTEP/threads-cv.pdf]. 
<!-- /jumpto -->
 
<!-- bodytext -->
'''Barriers''' [http://en.wikipedia.org/wiki/Barrier_(computer_science)] : This form of synchronization introduces a common stop point for multiple threads and processes. It ensures that all threads/processes reach this barrier before continuing any further.
<p>Current page address: <a href="http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_506_Spring_2013/3a_bs" class="external free" rel="nofollow">http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_506_Spring_2013/3a_bs</a>
 
</p><p>Page started with: <a href="http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_506_Spring_2011/ch3_ab" class="external free" rel="nofollow">http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_506_Spring_2011/ch3_ab</a>
Case 1, mentioned in the previous subsection, can be addressed using Barrier synchronization. Cases 2 and 3 can be addressed using Semaphores, Mutexes and Conditional Variables.
</p>
 
<table id="toc" class="toc"><tr><td><div id="toctitle"><h2>Contents</h2></div>
The following section discusses two libraries that implement the aforementioned synchronization mechanisms.
<ul>
 
<li class="toclevel-1 tocsection-1"><a href="#Overview"><span class="tocnumber">1</span> <span class="toctext">Overview</span></a></li>
== Libraries<ref>http://linux.die.net/man/3/</ref> ==
<li class="toclevel-1 tocsection-2"><a href="#Synchronization"><span class="tocnumber">2</span> <span class="toctext">Synchronization</span></a></li>
 
<li class="toclevel-1 tocsection-3"><a href="#Libraries.5B3.5D"><span class="tocnumber">3</span> <span class="toctext">Libraries<sup>[3]</sup></span></a>
 
<ul>
=== 1. Semaphore.h ===
<li class="toclevel-2 tocsection-4"><a href="#Semaphore.h"><span class="tocnumber">3.1</span> <span class="toctext">Semaphore.h</span></a>
-----------------------
<ul>
<li class="toclevel-3 tocsection-5"><a href="#Initializing_a_semaphore"><span class="tocnumber">3.1.1</span> <span class="toctext">Initializing a semaphore</span></a></li>
A [http://en.wikipedia.org/wiki/Semaphore_(programming) semaphore] is special [http://en.wikipedia.org/wiki/Variable_(computer_science) variable] that acts similar to a [http://en.wikipedia.org/wiki/Lock_(computer_science) lock]. For a process to enter into the critical section it must be able to acquire the semaphore. If the semaphore cannot be acquired, then the process is “put to [http://en.wikipedia.org/wiki/Sleep_(system_call) sleep]” and the processor is then used for another process. This means the processes [http://en.wikipedia.org/wiki/CPU_cache cache] is saved off in a place where it can be retrieved when the process is “woken up”. Once the semaphore is available the “sleeping” process is woken up and obtains the semaphore and proceeds in to the critical section.A simple way to execute a semaphore would be to use the following functions for various operations on semaphores;
<li class="toclevel-3 tocsection-6"><a href="#Locking_the_semaphore"><span class="tocnumber">3.1.2</span> <span class="toctext">Locking the semaphore</span></a></li>
 
<li class="toclevel-3 tocsection-7"><a href="#Releasing_the_semaphore"><span class="tocnumber">3.1.3</span> <span class="toctext">Releasing the semaphore</span></a></li>
====Initializing a semaphore====
<li class="toclevel-3 tocsection-8"><a href="#Pseudo_Code"><span class="tocnumber">3.1.4</span> <span class="toctext">Pseudo Code</span></a></li>
 
</ul>
'''•  ''int sem_init(sem_t *sem, int pshared, unsigned int value):'''''
</li>
This function [http://en.wikipedia.org/wiki/Initialization_(programming) initializes] the unnamed semaphore at the address pointed to by sem. Value is the initial value of the semaphore. The variable pshared is indicative of whether the semaphore is shared between threads or processes. If its value is zero it is shared between [http://en.wikipedia.org/wiki/Threads_(computer_science) threads] else it is shared between [http://en.wikipedia.org/wiki/Process_(computing) processes].
<li class="toclevel-2 tocsection-9"><a href="#Pthread.h"><span class="tocnumber">3.2</span> <span class="toctext">Pthread.h</span></a>
 
<ul>
Return Value:
<li class="toclevel-3 tocsection-10"><a href="#Mutexes"><span class="tocnumber">3.2.1</span> <span class="toctext">Mutexes</span></a>
<ul>
<li class="toclevel-4 tocsection-11"><a href="#Initialising_the_mutex"><span class="tocnumber">3.2.1.1</span> <span class="toctext">Initialising the mutex</span></a></li>
<li class="toclevel-4 tocsection-12"><a href="#Destroying_the_mutex"><span class="tocnumber">3.2.1.2</span> <span class="toctext">Destroying the mutex</span></a></li>
<li class="toclevel-4 tocsection-13"><a href="#Locking_the_mutex"><span class="tocnumber">3.2.1.3</span> <span class="toctext">Locking the mutex</span></a></li>
<li class="toclevel-4 tocsection-14"><a href="#Unlocking_the_mutex"><span class="tocnumber">3.2.1.4</span> <span class="toctext">Unlocking the mutex</span></a></li>
<li class="toclevel-4 tocsection-15"><a href="#Pseudo_code_2"><span class="tocnumber">3.2.1.5</span> <span class="toctext">Pseudo code</span></a></li>
<li class="toclevel-4 tocsection-16"><a href="#Avoiding_Deadlock.5B12.5D"><span class="tocnumber">3.2.1.6</span> <span class="toctext">Avoiding Deadlock<sup>[12]</sup></span></a></li>
</ul>
</li>
<li class="toclevel-3 tocsection-17"><a href="#Joins"><span class="tocnumber">3.2.2</span> <span class="toctext">Joins</span></a></li>
<li class="toclevel-3 tocsection-18"><a href="#Conditional_Variables"><span class="tocnumber">3.2.3</span> <span class="toctext">Conditional Variables</span></a>
<ul>
<li class="toclevel-4 tocsection-19"><a href="#Creating.2FDestroying"><span class="tocnumber">3.2.3.1</span> <span class="toctext">Creating/Destroying</span></a></li>
<li class="toclevel-4 tocsection-20"><a href="#Waiting_on_condition"><span class="tocnumber">3.2.3.2</span> <span class="toctext">Waiting on condition</span></a></li>
<li class="toclevel-4 tocsection-21"><a href="#Waking_thread_based_on_condition"><span class="tocnumber">3.2.3.3</span> <span class="toctext">Waking thread based on condition</span></a></li>
</ul>
</li>
<li class="toclevel-3 tocsection-22"><a href="#Barriers"><span class="tocnumber">3.2.4</span> <span class="toctext">Barriers</span></a>
<ul>
<li class="toclevel-4 tocsection-23"><a href="#Initialising_the_Barrier"><span class="tocnumber">3.2.4.1</span> <span class="toctext">Initialising the Barrier</span></a></li>
<li class="toclevel-4 tocsection-24"><a href="#Barrier_Wait"><span class="tocnumber">3.2.4.2</span> <span class="toctext">Barrier Wait</span></a></li>
<li class="toclevel-4 tocsection-25"><a href="#Destroying_the_Barrier"><span class="tocnumber">3.2.4.3</span> <span class="toctext">Destroying the Barrier</span></a></li>
<li class="toclevel-4 tocsection-26"><a href="#Pseudo_code_3"><span class="tocnumber">3.2.4.4</span> <span class="toctext">Pseudo code</span></a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li class="toclevel-1 tocsection-27"><a href="#References"><span class="tocnumber">4</span> <span class="toctext">References</span></a></li>
<li class="toclevel-1 tocsection-28"><a href="#Quiz"><span class="tocnumber">5</span> <span class="toctext">Quiz</span></a></li>
</ul>
</td></tr></table>
<h2><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=1" title="Edit section: Overview">edit</a>]</span> <span class="mw-headline" id="Overview"> Overview </span></h2>
<p>The main goal of this wiki is to explain which architectural mechanisms are used by library functions for DOALL, DOACROSS, and DOPIPE parallelism, reduction, and functional parallelism in various architectures.
</p>
<h2><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=2" title="Edit section: Synchronization">edit</a>]</span> <span class="mw-headline" id="Synchronization"> Synchronization </span></h2>
<p>When using any <a href="http://en.wikipedia.org/wiki/Parallel_programming_model" class="external text" rel="nofollow">parallel programming model</a>, <a href="http://en.wikipedia.org/wiki/Synchronization_(computer_science)" class="external text" rel="nofollow">synchronization</a><sup id="cite_ref-0" class="reference"><a href="#cite_note-0">[1]</a></sup> is needed to guarantee accuracy of the overall program. The following are a few example situations where synchronization<sup id="cite_ref-1" class="reference"><a href="#cite_note-1">[2]</a></sup> will be needed.
</p><p><br />
•  The code following the parallelized loop requires that all of the parallel <a href="http://en.wikipedia.org/wiki/Process_(computer_science)" class="external text" rel="nofollow">processes</a> be completed before advancing. It cannot be triggered simply by one of the processes completing.
</p><p>•  A portion of code in the middle of a parallelized section MUST be executed in a very particular order so that <a href="http://en.wikipedia.org/wiki/Global_variable" class="external text" rel="nofollow">global variables</a> used across processes get read and written in the proper order. This is known as the <a href="http://en.wikipedia.org/wiki/Critical_section" class="external text" rel="nofollow">critical section</a>.
</p><p>•  Multiple processes must update a global variable in such a way that one process does not overwrite the updates of a different process. (i.e. SUM = SUM + &lt;process update&gt;).
</p><p><br />
These are just a few examples. Every architecture implements synchronization in a unique way using different types of mechanisms. The subsequent section will highlight the following that are used to achieve synchronization:
</p><p>1. Semaphore.h
</p><p>2. Pthread.h
</p>
<h2><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=3" title="Edit section: Libraries[3]">edit</a>]</span> <span class="mw-headline" id="Libraries.5B3.5D"> Libraries<sup id="cite_ref-2" class="reference"><a href="#cite_note-2">[3]</a></sup> </span></h2>
<h3><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=4" title="Edit section: Semaphore.h">edit</a>]</span> <span class="mw-headline" id="Semaphore.h"> Semaphore.h </span></h3>
<hr />
<p>A <a href="http://en.wikipedia.org/wiki/Semaphore_(programming)" class="external text" rel="nofollow">semaphore</a> is special <a href="http://en.wikipedia.org/wiki/Variable_(computer_science)" class="external text" rel="nofollow">variable</a> that acts similar to a <a href="http://en.wikipedia.org/wiki/Lock_(computer_science)" class="external text" rel="nofollow">lock</a>. For a process to enter into the critical section it must be able to acquire the semaphore. If the semaphore cannot be acquired, then the process is “put to <a href="http://en.wikipedia.org/wiki/Sleep_(system_call)" class="external text" rel="nofollow">sleep</a>” and the processor is then used for another process. This means the processes <a href="http://en.wikipedia.org/wiki/CPU_cache" class="external text" rel="nofollow">cache</a> is saved off in a place where it can be retrieved when the process is “woken up”. Once the semaphore is available the “sleeping” process is woken up and obtains the semaphore and proceeds in to the critical section.A simple way to execute a semaphore would be to use the following functions for various operations on semaphores;
</p><p><br />
</p>
<h4><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=5" title="Edit section: Initializing a semaphore">edit</a>]</span> <span class="mw-headline" id="Initializing_a_semaphore">Initializing a semaphore</span></h4>
<p><b>•  <i>int sem_init(sem_t *sem, int pshared, unsigned int value):</i></b>
This function <a href="http://en.wikipedia.org/wiki/Initialization_(programming)" class="external text" rel="nofollow">initializes</a> the unnamed semaphore at the address pointed to by sem. Value is the initial value of the semaphore. The variable pshared is indicative of whether the semaphore is shared between threads or processes. If its value is zero it is shared between <a href="http://en.wikipedia.org/wiki/Threads_(computer_science)" class="external text" rel="nofollow">threads</a> else it is shared between <a href="http://en.wikipedia.org/wiki/Process_(computing)" class="external text" rel="nofollow">processes</a>.
</p><p>Return Value:
sem_init() returns 0 on success; on error, -1 is returned, and errno is set to indicate the error.
sem_init() returns 0 on success; on error, -1 is returned, and errno is set to indicate the error.
</p>
 
<h4><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=6" title="Edit section: Locking the semaphore">edit</a>]</span> <span class="mw-headline" id="Locking_the_semaphore">Locking the semaphore</span></h4>
====Locking the semaphore====
<p><b>•  <i>int sem_wait(sem_t *sem):</i></b> This function decrements (locks) the semaphore pointed to by sem. Decrement will only proceed if the value of the semaphore is greater than zero. If its value is zero, then the call blocks till the value of the semaphore becomes positive so that it can acquire it or a <a href="http://en.wikipedia.org/wiki/Signal_handler" class="external text" rel="nofollow">signal handler</a> interrupts the call.
By acquiring a lock, it is ensured that the execution of other processes or threads (trying to access the shared resource) is postponed indefinitely. Blocking the execution of a higher priority thread or a thread responsible for performing real time operations may be undesired, thus highlighting the necessity of [http://en.wikipedia.org/wiki/Non-blocking_synchronization Non-Blocking statements].
</p><p><b>•  <i>int sem_trywait(sem_t *sem):</i></b>
Depending upon the application, we may want a blocking or non blocking assignment of locks. This is achieved using the following constructs:
This function is the same as sem_wait(), except that if the decrement cannot be immediately performed, then call returns an error (errno set to EAGAIN<sup id="cite_ref-3" class="reference"><a href="#cite_note-3">[4]</a></sup>) instead of <a href="http://en.wikipedia.org/wiki/Blocking_(computing)" class="external text" rel="nofollow">blocking</a>.
</p><p><b>•  <i>int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout):</i></b>
'''•  ''int sem_wait(sem_t *sem):[Blocking]''''' This function decrements (locks) the semaphore pointed to by sem. Decrement will only proceed if the value of the semaphore is greater than zero. If its value is zero, then the call blocks till the value of the semaphore becomes positive so that it can acquire it or a [http://en.wikipedia.org/wiki/Signal_handler signal handler] interrupts the call.
 
'''•  ''int sem_trywait(sem_t *sem):[Non-Blocking]'''''
This function is the same as sem_wait(), except that if the decrement cannot be immediately performed, then call returns an error (errno set to EAGAIN<ref>http://www-numi.fnal.gov/computing/minossoft/releases/R2.3/WebDocs/Errors/unix_system_errors.html</ref>) instead of [http://en.wikipedia.org/wiki/Blocking_(computing) blocking].
 
'''•  ''int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout):[Blocking with Timeout]'''''
This function is also the same as sem_wait(), except that abs_timeout specifies a limit on the amount of time that the call should block if the decrement cannot be immediately performed. The abs_timeout argument points to a structure that specifies an absolute timeout in seconds and nanoseconds. This structure is defined as follows:
This function is also the same as sem_wait(), except that abs_timeout specifies a limit on the amount of time that the call should block if the decrement cannot be immediately performed. The abs_timeout argument points to a structure that specifies an absolute timeout in seconds and nanoseconds. This structure is defined as follows:
</p>
<pre>      struct timespec  
      struct timespec  
      {
      {
      time_t tv_sec;          /* Seconds */
      time_t tv_sec;          /* Seconds */
      long  tv_nsec;        /* Nanoseconds [0 .. 999999999] */
      long  tv_nsec;        /* Nanoseconds [0 .. 999999999] */
      };
      };
</pre>
 
<p>If the timeout has already expired by the time of the call, and the semaphore could not be locked immediately, then sem_timedwait() fails with a timeout error (errno set to ETIMEDOUT<sup id="cite_ref-4" class="reference"><a href="#cite_note-4">[5]</a></sup>). If the operation can be performed immediately, then sem_timedwait() never fails with a timeout error, regardless of the value of abs_timeout. Furthermore, the validity of abs_timeout is not checked in this case.
If the timeout has already expired by the time of the call, and the semaphore could not be locked immediately, then sem_timedwait() fails with a timeout error (errno set to ETIMEDOUT<ref>http://pubs.opengroup.org/onlinepubs/7908799/xsh/errors.html</ref>). If the operation can be performed immediately, then sem_timedwait() never fails with a timeout error, regardless of the value of abs_timeout. Furthermore, the validity of abs_timeout is not checked in this case.
</p><p>Return Value:
 
All of these functions return 0 on success; on error, the value of the semaphore is left unchanged, -1 is returned, and errno<sup id="cite_ref-5" class="reference"><a href="#cite_note-5">[6]</a></sup> is set to indicate the error.
Return Value:
</p>
All of these functions return 0 on success; on error, the value of the semaphore is left unchanged, -1 is returned, and errno<ref>http://www.kernel.org/doc/man-pages/online/pages/man3/errno.3.html</ref> is set to indicate the error.
<h4><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=7" title="Edit section: Releasing the semaphore">edit</a>]</span> <span class="mw-headline" id="Releasing_the_semaphore"> Releasing the semaphore </span></h4>
 
<p><b>•  <i>int sem_post(sem_t *sem):</i></b> This function increments (unlocks) the semaphore pointed to by sem, thus making the value of the semaphore positive. Some other process can now acquire it.
==== Releasing the semaphore ====
</p><p>Return Value: sem_post() returns 0 on success; on error, the value of the semaphore is left unchanged, -1 is returned, and errno is set to indicate the error.
 
</p>
'''•  ''int sem_post(sem_t *sem):''''' This function increments (unlocks) the semaphore pointed to by sem, thus making the value of the semaphore positive. Some other process can now acquire it.
<h4><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=8" title="Edit section: Pseudo Code">edit</a>]</span> <span class="mw-headline" id="Pseudo_Code"><b>Pseudo Code</b></span></h4>
 
<pre>    <code>
Return Value: sem_post() returns 0 on success; on error, the value of the semaphore is left unchanged, -1 is returned, and errno is set to indicate the error.
    sem_t *sem;  
 
    int pshared;
===='''Pseudocode'''====
    unsigned int value;
 
    int i = sem_init(sem, pshared, value);                            /*initialize the semaphore*/
      <code>
    int wait=sem_wait(sem);                                          /*will decrement the value of the semaphore i.e. acquire the lock */
      sem_t *sem;  
   
      int pshared;
    if(wait==-1)
      unsigned int value;
        printf(“Error occurred, the value of the semaphore was not decremented”);
      int i = sem_init(sem, pshared, value);                            /*initialize the semaphore*/
   
      int wait=sem_wait(sem);                                          /*will decrement the value of the semaphore i.e. acquire the lock */
    /*critical section;*/
     
    int post=sem_post(sem);                                          /*will increment the value of the semaphore i.e. release the lock*/
      if(wait==-1)
    if(post==-1)
          printf(“Error occurred, the value of the semaphore was not decremented”);
        printf(“Error occurred, the value of the semaphore was not incremented”);
     
    </code>
      /*critical section;*/
</pre>
      int post=sem_post(sem);                                          /*will increment the value of the semaphore i.e. release the lock*/
<h3><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=9" title="Edit section: Pthread.h">edit</a>]</span> <span class="mw-headline" id="Pthread.h"> Pthread.h </span></h3>
      if(post==-1)
<hr />
          printf(“Error occurred, the value of the semaphore was not incremented”);
<p>POSIX threads<sup id="cite_ref-6" class="reference"><a href="#cite_note-6">[7]</a></sup>, usually referred to as <a href="http://en.wikipedia.org/wiki/Pthread" class="external text" rel="nofollow">pthreads</a> defines a set of programming language <a href="http://en.wikipedia.org/wiki/Data_type" class="external text" rel="nofollow">types</a>,<a href="http://en.wikipedia.org/wiki/Function_(computer_science)" class="external text" rel="nofollow">functions</a> and constants.It is implemented with a pthread.h <a href="http://en.wikipedia.org/wiki/Header_file" class="external text" rel="nofollow">header file</a> and a thread library. The pthread library provides the following synchronization mechanisms:
      </code>
</p><p>1. Mutexes
 
</p><p>2. Joins
=== 2. Pthread.h ===
</p><p>3. Conditional Variables
----------------------------
</p><p>4. Barriers
 
</p><p><br />
POSIX threads<ref>http://maxim.int.ru/bookshelf/PthreadsProgram/toc.html</ref>, usually referred to as [http://en.wikipedia.org/wiki/Pthread pthreads] defines a set of programming language [http://en.wikipedia.org/wiki/Data_type types],[http://en.wikipedia.org/wiki/Function_(computer_science) functions] and constants.It is implemented with a pthread.h [http://en.wikipedia.org/wiki/Header_file header file] and a thread library. The pthread library provides the following synchronization mechanisms:
</p>
 
<h4><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=10" title="Edit section: Mutexes">edit</a>]</span> <span class="mw-headline" id="Mutexes"> Mutexes </span></h4>
1. Mutexes
<p><i><b>Mutual Exclusion Lock</b></i><sup id="cite_ref-7" class="reference"><a href="#cite_note-7">[8]</a></sup>, mutex in short is another synchronization method and is used to avoid <a href="http://en.wikipedia.org/wiki/Race_condition" class="external text" rel="nofollow">race conditions</a>. In cases leading to data inconsistencies,like when multiple threads are to be prevented from operating on the same memory location simultaneously or when a specific order of operation is expected, mutexes are used.It blocks access to variables by other threads.
 
Mutexes are in particular used to protect a critical region (“a segment of memory”) from other threads<sup id="cite_ref-8" class="reference"><a href="#cite_note-8">[9]</a></sup>.
2. Joins
</p><p>The following are the functions for using mutexes:<sup id="cite_ref-9" class="reference"><a href="#cite_note-9">[10]</a></sup>
 
</p>
3. Conditional Variables
<h5><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=11" title="Edit section: Initialising the mutex">edit</a>]</span> <span class="mw-headline" id="Initialising_the_mutex">Initialising the mutex </span></h5>
 
<p><b>•  <i>pthread_mutex_init (pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr):</i></b>
4. Barriers
 
==== Mutexes ====
 
'''''Mutual Exclusion Lock'''''<ref>http://docs.oracle.com/cd/E19963-01/html/821-1601/sync-28983.html</ref>, mutex in short is another synchronization method and is used to avoid [http://en.wikipedia.org/wiki/Race_condition race conditions]. In cases leading to data inconsistencies,like when multiple threads are to be prevented from operating on the same memory location simultaneously or when a specific order of operation is expected, mutexes are used.It blocks access to variables by other threads.
Mutexes are in particular used to protect a critical region (“a segment of memory”) from other threads<ref>Raghunathan, S.; , "Extending Inter-process Synchronization with Robust Mutex and Variants in Condition Wait," Parallel and Distributed Systems, 2008. ICPADS '08. 14th IEEE International Conference on , vol., no., pp.121-128, 8-10 Dec. 2008</ref>.
 
The following are the functions for using mutexes:<ref>http://pic.dhe.ibm.com/infocenter/aix/v7r1/index.jsp?topic=%2Fcom.ibm.aix.genprogc%2Fdoc%2Fgenprogc%2Fmutexes.htm</ref>
 
=====Initialising the mutex =====
 
'''•  ''pthread_mutex_init (pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr):'''''
The mutex referenced by the mutex is initialised with the attributes specified by attr using this function. The default mutex attributes are used if attribute passed is NULL.Passing a NULL attribute implies passing the address of a default mutex. The state of the mutex is initialized and unlocked,upon successful initialization.
The mutex referenced by the mutex is initialised with the attributes specified by attr using this function. The default mutex attributes are used if attribute passed is NULL.Passing a NULL attribute implies passing the address of a default mutex. The state of the mutex is initialized and unlocked,upon successful initialization.
</p><p>The pthread_mutex_init can be used to reinitialize an already destroyed mutex,but attempting to initialize an already initialized mutex results in undefined behavior.
 
The <a href="http://en.wikipedia.org/wiki/Macro_(computer_science)" class="external text" rel="nofollow">macro</a> <a href="http://pic.dhe.ibm.com/infocenter/aix/v7r1/index.jsp?topic=%2Fcom.ibm.aix.basetechref%2Fdoc%2Fbasetrf1%2FPTHREAD_MUTEX_INITIALIZER.htm" class="external text" rel="nofollow">PTHREAD_MUTEX_INITIALIZER</a> is used to initialize mutexes that are statically allocated in cases where default mutex attributes are appropriate. It is dynamic initialization by a call with parameter attr specified as NULL to pthread_mutex_init() but in this case no error checks are performed.
The pthread_mutex_init can be used to reinitialize an already destroyed mutex,but attempting to initialize an already initialized mutex results in undefined behavior.
</p><p>Return Value: The function returns zero on success; otherwise, an error number is returned to indicate the error.
The [http://en.wikipedia.org/wiki/Macro_(computer_science) macro] [http://pic.dhe.ibm.com/infocenter/aix/v7r1/index.jsp?topic=%2Fcom.ibm.aix.basetechref%2Fdoc%2Fbasetrf1%2FPTHREAD_MUTEX_INITIALIZER.htm PTHREAD_MUTEX_INITIALIZER] is used to initialize mutexes that are statically allocated in cases where default mutex attributes are appropriate. It is dynamic initialization by a call with parameter attr specified as NULL to pthread_mutex_init() but in this case no error checks are performed.
</p>
 
<h5><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=12" title="Edit section: Destroying the mutex">edit</a>]</span> <span class="mw-headline" id="Destroying_the_mutex"> Destroying the mutex</span></h5>
Return Value: The function returns zero on success; otherwise, an error number is returned to indicate the error.
<p><b>•  <i>pthread_mutex_destroy (pthread_mutex_t *mutex):</i></b>
 
===== Destroying the mutex=====
 
'''•  ''pthread_mutex_destroy (pthread_mutex_t *mutex):'''''
This function is used to destroy a mutex which is no longer needed. The function destroys the mutex object passed by mutex attribute and hence the mutex object becomes uninitialized. pthread_mutex_destroy() sets the object referenced to an invalid value.
This function is used to destroy a mutex which is no longer needed. The function destroys the mutex object passed by mutex attribute and hence the mutex object becomes uninitialized. pthread_mutex_destroy() sets the object referenced to an invalid value.
A  destroyed  mutex object can be reinitialized using pthread_mutex_init().A mutex cannot be referenced after it is destroyed.It is advised to destroy an initialized mutex that is unlocked. Attempting to destroy a locked mutex results in undefined behavior.
A  destroyed  mutex object can be reinitialized using pthread_mutex_init().A mutex cannot be referenced after it is destroyed.It is advised to destroy an initialized mutex that is unlocked. Attempting to destroy a locked mutex results in undefined behavior.
</p><p>Return Value: The function returns zero on success; otherwise, an error number is returned to indicate the error.
 
</p>
Return Value: The function returns zero on success; otherwise, an error number is returned to indicate the error.
<h5><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=13" title="Edit section: Locking the mutex">edit</a>]</span> <span class="mw-headline" id="Locking_the_mutex">Locking the mutex</span></h5>
 
<p><b>•  <i>pthread_mutex_lock (pthread_mutex_t *mutex):</i></b>
=====Locking the mutex=====
 
'''•  ''pthread_mutex_lock (pthread_mutex_t *mutex):'''''
This function is used to lock the mutex passed. If the mutex is already locked by another process, the calling thread blocks until the mutex is unlocked by the other process.This operation returns the mutex object referenced by mutex in the locked state with the calling thread as its owner.Error checking is provided if the mutex is of type PTHREAD_MUTEX_ERRORCHECK. Error shall be returned if a thread attempts to relock a mutex that it has already locked or if a thread attempts to unlock a mutex that it has not locked or a mutex which is unlocked.
This function is used to lock the mutex passed. If the mutex is already locked by another process, the calling thread blocks until the mutex is unlocked by the other process.This operation returns the mutex object referenced by mutex in the locked state with the calling thread as its owner.Error checking is provided if the mutex is of type PTHREAD_MUTEX_ERRORCHECK. Error shall be returned if a thread attempts to relock a mutex that it has already locked or if a thread attempts to unlock a mutex that it has not locked or a mutex which is unlocked.
</p><p>Mutexes of type,PTHREAD_MUTEX_RECURSIVE<sup id="cite_ref-10" class="reference"><a href="#cite_note-10">[11]</a></sup> maintain a lock count. The lock count is set to one when a mutex is acquired by a thread successfully for the first time. And the lock count is incremented in units of one every time a thread relocks this mutex. Each time the thread unlocks the mutex, the lock count is decremented by one. When the lock count reaches zero, the mutex becomes available for other threads to acquire.An error is returned if a thread attempts to unlock a mutex that it has not locked or a mutex which is unlocked.
 
</p><p>If the mutex type is PTHREAD_MUTEX_DEFAULT, attempting to recursively lock the mutex or attempting to unlock the mutex if it was not locked by the calling thread or attempting to unlock the mutex if it is not locked results in undefined behavior.If a signal is delivered to a thread waiting for a mutex, upon return from the signal handler the thread shall resume waiting for the mutex as if it was not interrupted.
Mutexes of type,PTHREAD_MUTEX_RECURSIVE<ref>http://developer.apple.com/library/ios/#documentation/System/Conceptual/ManPages_iPhoneOS/man3/pthread_mutexattr_settype.3.html</ref> maintain a lock count. The lock count is set to one when a mutex is acquired by a thread successfully for the first time. And the lock count is incremented in units of one every time a thread relocks this mutex. Each time the thread unlocks the mutex, the lock count is decremented by one. When the lock count reaches zero, the mutex becomes available for other threads to acquire.An error is returned if a thread attempts to unlock a mutex that it has not locked or a mutex which is unlocked.
</p><p>Return Value: The functions return a zero on success; otherwise, an error number is returned to indicate the error.
 
</p>
If the mutex type is PTHREAD_MUTEX_DEFAULT, attempting to recursively lock the mutex or attempting to unlock the mutex if it was not locked by the calling thread or attempting to unlock the mutex if it is not locked results in undefined behavior.If a signal is delivered to a thread waiting for a mutex, upon return from the signal handler the thread shall resume waiting for the mutex as if it was not interrupted.
<h5><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=14" title="Edit section: Unlocking the mutex">edit</a>]</span> <span class="mw-headline" id="Unlocking_the_mutex"> Unlocking the mutex</span></h5>
 
<p><b>•  <i>pthread_mutex_unlock (pthread_mutex_t *mutex):</i></b> This function is used to release a mutex that is previously locked.The function shall release the mutex object referenced by  mutex. The  manner  in which a mutex is released is dependent upon the mutex's type attribute.If  there  are  threads  blocked on the mutex object referenced by mutex when pthread_mutex_unlock() is called, resulting in the mutex becoming available, the <a href="http://en.wikipedia.org/wiki/Scheduling_(computing)" class="external text" rel="nofollow">scheduling</a> policy shall determine which thread shall acquire the mutex. An error is returned if mutex is already unlocked or owned by another thread.
Return Value: The functions return a zero on success; otherwise, an error number is returned to indicate the error.
</p><p>Return Value: The functions return a zero on success; otherwise, an error number is returned to indicate the error.
 
</p>
===== Unlocking the mutex=====
<h5><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=15" title="Edit section: Pseudo code">edit</a>]</span> <span class="mw-headline" id="Pseudo_code_2"><b>Pseudo code</b></span></h5>
 
<pre>   <code>
'''•  ''pthread_mutex_unlock (pthread_mutex_t *mutex):''''' This function is used to release a mutex that is previously locked.The function shall release the mutex object referenced by  mutex. The  manner  in which a mutex is released is dependent upon the mutex's type attribute.If  there  are  threads  blocked on the mutex object referenced by mutex when pthread_mutex_unlock() is called, resulting in the mutex becoming available, the [http://en.wikipedia.org/wiki/Scheduling_(computing) scheduling] policy shall determine which thread shall acquire the mutex. An error is returned if mutex is already unlocked or owned by another thread.
     pthread_mutex_t *mutex,
     const pthread_mutexattr_t *attr;
Return Value: The functions return a zero on success; otherwise, an error number is returned to indicate the error.
     int p, p1, pu, pd;
 
     p = pthread_mutex_init(mutex, attr);
====='''Pseudocode'''=====
    <code>
    pthread_mutex_t *mutex,
    const pthread_mutexattr_t *attr;
    int p, p1, pu, pd;
    p = pthread_mutex_init(mutex, attr);
   
    if(p!=0)
          printf("Error occurred mutex was not created”);
   
    pl = pthread_mutex_lock(mutex);   
    if(pl!=0)
          printf("Error occurred mutex was not locked”);
   
    /*critical section*/
    pu = pthread_mutex_unlock(mutex);
    if(pu!=0)
          printf("Error occurred mutex was not unlocked”);
   
    pd = pthread_mutex_destroy(mutex);
    if(pd!=0)
          printf("Error occurred mutex was not destroyed”);
    </code>
 
====='''Avoiding Deadlock<ref>http://www2.chrishardick.com:1099/Notes/Computing/C/pthreads/mutexes.html</ref>'''=====
 
[http://en.wikipedia.org/wiki/Deadlock Deadlocks] occur when the program holds more than one mutex. A classic example of deadlock is;
 
'''Thread 1:'''
 
    lock mutex_a
    |
    lock mutex_b
    -blocked forever waiting for mutex_b
 
'''Thread 2:'''
 
    lock mutex_b
    |
    lock mutex_a
    -blocked forever waiting for mutex a
 
 
Few common techniques<ref>http://pages.cs.wisc.edu/~remzi/Classes/537/Fall2011/Book/threads-deadlock.pdf</ref> exist which can be used to avoid deadlocks, which are;
 
1. Establish a locking hierarchy.<ref>http://software.intel.com/sites/products/documentation/doclib/stdxe/2013/inspectorxe/lin/ug_docs/GUID-38B68BDA-257C-4D4E-9AC9-B0B2698AD950.htm</ref>
 
2. [http://en.wikipedia.org/wiki/Spinlock Spinlock.]
 
3. Chaining.
 
 
'''1. Establish a locking hierarchy:'''
 
• A hierarchy needs to be established to hold multiple [http://en.wikipedia.org/wiki/Lock_(computer_science) locks].
 
• A rule could be established such that in order to lock mutex_a and mutex_b, mutex_a must be locked before mutex_b.
 
• If unnecessary then both locks should not be held simultaneously.
 
• Order of locking the mutexes must be maintained.
 
• Mutexes can be unlocked in any order that is preferred by the program, because unlocking doesn't create deadlocks.
 
• Another function must be formulated in order to unlock the set of mutexes.
 
 
'''Thread 1:'''
     lock mutex_a
     lock mutex_b
      
     //perform processing
      
      
     if(p!=0)
     unlock mutex_a
        printf("Error occurred mutex was not created”);
    unlock mutex_b
    ...
 
'''Thread 2:'''
    lock mutex_a(blocked)
      
      
     pl = pthread_mutex_lock(mutex);   
     wake up(obtained mutex_a)
     if(pl!=0)
     lock mutex_b
        printf("Error occurred mutex was not locked”);
      
      
     /*critical section*/
     //perform processing
    pu = pthread_mutex_unlock(mutex);
    if(pu!=0)
        printf("Error occurred mutex was not unlocked”);
      
      
     pd = pthread_mutex_destroy(mutex);
     unlock mutex_a
    if(pd!=0)
    unlock mutex_b
        printf("Error occurred mutex was not destroyed”);
    ...
    </code>
 
</pre>
'''2. Spin lock:'''
<h5><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=16" title="Edit section: Avoiding Deadlock[12]">edit</a>]</span> <span class="mw-headline" id="Avoiding_Deadlock.5B12.5D"><b>Avoiding Deadlock<sup id="cite_ref-11" class="reference"><a href="#cite_note-11">[12]</a></sup></b></span></h5>
 
<p><a href="http://en.wikipedia.org/wiki/Deadlock" class="external text" rel="nofollow">Deadlocks</a> occur when the program holds more than one mutex. A classic example of deadlock is;
• The first mutex can be locked without any [http://en.wikipedia.org/wiki/Constraint constraints]. But from here on to lock additional mutexes non-blocking mutexes<ref>http://docs.oracle.com/cd/E19683-01/806-6867/sync-36993/index.html</ref> must be used (pthread_mutex_trylock())
</p><p><b>Thread 1:</b>
 
</p>
• In case of a failure in any lock, unlock in reverse order and try again.
<pre>  lock mutex_a
 
  |
• This method of unlocking in the reverse order reduces the spinning for other threads.
  lock mutex_b
 
  -blocked forever waiting for mutex_b
 
</pre>
'''Thread 1:'''
<p><b>Thread 2:</b>
 
</p>
    lock mutex_a
<pre>  lock mutex_b
    try-lock mutex_b
  |
    |
  lock mutex_a
    perform processing  
  -blocked forever waiting for mutex a
    |  
</pre>
    unlock mutex_b
<p><br />
    unlock mutex_a   
Few common techniques<sup id="cite_ref-12" class="reference"><a href="#cite_note-12">[13]</a></sup> exist which can be used to avoid deadlocks, which are;
    |         
</p><p>1. Establish a locking hierarchy.<sup id="cite_ref-13" class="reference"><a href="#cite_note-13">[14]</a></sup>
    ...
</p><p>2. <a href="http://en.wikipedia.org/wiki/Spinlock" class="external text" rel="nofollow">Spinlock.</a>
 
</p><p>3. Chaining.
'''Thread 2:'''
</p><p><br />
 
<b>1. Establish a locking hierarchy:</b>
    lock mutex_a (blocked)
</p><p>• A hierarchy needs to be established to hold multiple <a href="http://en.wikipedia.org/wiki/Lock_(computer_science)" class="external text" rel="nofollow">locks</a>.
   
</p><p>• A rule could be established such that in order to lock mutex_a and mutex_b, mutex_a must be locked before mutex_b.
    wake up (obtained mutex_a)
</p><p>• If unnecessary then both locks should not be held simultaneously.
    try-lock mutex_b
</p><p>• Order of locking the mutexes must be maintained.
    |
</p><p>• Mutexes can be unlocked in any order that is preferred by the program, because unlocking doesn't create deadlocks.
    perform processing
</p><p>• Another function must be formulated in order to unlock the set of mutexes.
    |
</p><p><br />
    unlock mutex_b
<b>Thread 1:</b>
    unlock mutex_a
</p>
 
<pre>  lock mutex_a
'''3. Chaining:'''
  lock mutex_b
 
 
• Traversing [http://en.wikipedia.org/wiki/Linked_list linked lists] and other [http://en.wikipedia.org/wiki/Tree_(data_structure)tree data structures].
  //perform processing
 
 
• A locking hierarchy is to be created, like Lock1, Lock2, Lock3, Unlock1, Lock4.
  unlock mutex_a
 
  unlock mutex_b
'''Thread 1'''
  ...
 
</pre>
    lock head node   
<p><b>Thread 2:</b>
    head node processing   
</p>
    |                     
<pre>  lock mutex_a(blocked)
    traverse branch locking first node  
 
    unlock head node  
  wake up(obtained mutex_a)
    first node processing
  lock mutex_b
 
 
==== Conditional Variables ====
  //perform processing
 
 
Conditional variables<ref>http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp</ref> are a kind of synchronization objects that are used to allow threads to wait for certain events to occur and are slightly more complex than mutexes. In order to ensure a safe and consistent [http://en.wikipedia.org/wiki/Serialization serialization], usage of condition variables requires the thread to cooperatively use a specific protocol which includes a mutex, a boolean [http://en.wikipedia.org/wiki/Predicate_(mathematical_logic) predicate] and the condition variable itself. The threads that are cooperating using condition variables can wait for a condition to occur, or can wake up other threads that are waiting for a condition.
  unlock mutex_a
 
  unlock mutex_b
The following are the functions used in conjunction with the conditional variable:
  ...
 
</pre>
=====Creating/Destroying=====
<p><b>2. Spin lock:</b>
 
</p><p>• The first mutex can be locked without any <a href="http://en.wikipedia.org/wiki/Constraint" class="external text" rel="nofollow">constraints</a>. But from here on to lock additional mutexes non-blocking mutexes<sup id="cite_ref-14" class="reference"><a href="#cite_note-14">[15]</a></sup> must be used (pthread_mutex_trylock())
'''•  ''int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr):'''''
</p><p>• In case of a failure in any lock, unlock in reverse order and try again.
</p><p>• This method of unlocking in the reverse order reduces the spinning for other threads.
</p><p><br />
<b>Thread 1:</b>
</p>
<pre>  lock mutex_a
  try-lock mutex_b
  |
  perform processing  
  |  
  unlock mutex_b
  unlock mutex_a   
  |         
  ...
</pre>
<p><b>Thread 2:</b>
</p>
<pre>  lock mutex_a (blocked)
 
  wake up (obtained mutex_a)
  try-lock mutex_b
  |
  perform processing
  |
  unlock mutex_b
  unlock mutex_a
</pre>
<p><b>3. Chaining:</b>
</p><p>• Traversing <a href="http://en.wikipedia.org/wiki/Linked_list" class="external text" rel="nofollow">linked lists</a> and other <a href="http://en.wikipedia.org/wiki/Tree_(data_structure)tree" class="external text" rel="nofollow">data structures</a>.
</p><p>• A locking hierarchy is to be created, like Lock1, Lock2, Lock3, Unlock1, Lock4.
</p><p><b>Thread 1</b>
</p>
<pre>  lock head node   
  head node processing   
  |                     
  traverse branch locking first node  
  unlock head node  
  first node processing
</pre>
<h4><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=17" title="Edit section: Joins">edit</a>]</span> <span class="mw-headline" id="Joins"> Joins </span></h4>
<p>A join is performed when one wants to wait for a thread to finish. A thread calling routine may launch multiple threads and then wait for them to finish to get the results.
</p><p><b>•  <i>pthread_join(pthread_t thread,void **value_ptr):</i></b> This function determines if a thread has completed before starting another task. The argument,thread refers to the thread id and value_ptr refers to the value passed from pthread_exit. This function suspends the execution of the calling thread until the target thread terminates, unless the target thread has already terminated.On return from a successful pthread_join() call with a non-NULL value_ptr argument, the value passed to <a href="http://www.kernel.org/doc/man-pages/online/pages/man3/pthread_exit.3.html" class="external text" rel="nofollow">pthread_exit()</a> by the terminating thread shall be made available in the location  referenced by value_ptr. When a pthread_join() returns successfully, the target thread has been terminated. The results of multiple simultaneous calls to pthread_join() specifying the same target thread are undefined. If the thread calling pthread_join() is canceled, then the target thread shall not be detached.
</p><p>Return Value: The function returns zero on success; otherwise, the error number is returned to indicate the error.
</p>
<h4><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=18" title="Edit section: Conditional Variables">edit</a>]</span> <span class="mw-headline" id="Conditional_Variables">  Conditional Variables </span></h4>
<p>Conditional variables<sup id="cite_ref-15" class="reference"><a href="#cite_note-15">[16]</a></sup> are a kind of synchronization objects that are used to allow threads to wait for certain events to occur and are slightly more complex than mutexes. In order to ensure a safe and consistent <a href="http://en.wikipedia.org/wiki/Serialization" class="external text" rel="nofollow">serialization</a>, usage of condition variables requires the thread to cooperatively use a specific protocol which includes a mutex, a boolean <a href="http://en.wikipedia.org/wiki/Predicate_(mathematical_logic)" class="external text" rel="nofollow">predicate</a> and the condition variable itself. The threads that are cooperating using condition variables can wait for a condition to occur, or can wake up other threads that are waiting for a condition.
</p><p>The following are the functions used in conjunction with the conditional variable:
</p>
<h5><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=19" title="Edit section: Creating/Destroying">edit</a>]</span> <span class="mw-headline" id="Creating.2FDestroying">Creating/Destroying</span></h5>
<p><b>•  <i>int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr):</i></b>
This function is used to initialize the conditional variable referenced by 'cond' with attributes referenced by 'attr'. Default condition variable attributes shall be used if attribute is NULL.It is same as passing the address of a default condition variable attributes object.Upon successful initialization, the conditional variable state is initialized. Attempting to initialize an already initialized condition variable results in undefined behavior.
This function is used to initialize the conditional variable referenced by 'cond' with attributes referenced by 'attr'. Default condition variable attributes shall be used if attribute is NULL.It is same as passing the address of a default condition variable attributes object.Upon successful initialization, the conditional variable state is initialized. Attempting to initialize an already initialized condition variable results in undefined behavior.
</p><p>Return Value: If successful the function returns zero; otherwise, an error number is returned to indicate the error.
 
</p><p><br />
Return Value: If successful the function returns zero; otherwise, an error number is returned to indicate the error.
<b>•  <i>pthread_cond_destroy(pthread_cond_t *cond):</i></b> This function destroys the given condition variable specified by cond; the object becomes, in  effect,  uninitialized.An implementation may cause pthread_cond_destroy() to set the object referenced by cond to an invalid value.An already destroyed condition variable object can be reinitialized using pthread_cond_init(); the results of otherwise referencing the object after it has been destroyed are undefined.
 
'''•  ''pthread_cond_destroy(pthread_cond_t *cond):''''' This function destroys the given condition variable specified by cond; the object becomes, in  effect,  uninitialized.An implementation may cause pthread_cond_destroy() to set the object referenced by cond to an invalid value.An already destroyed condition variable object can be reinitialized using pthread_cond_init(); the results of otherwise referencing the object after it has been destroyed are undefined.
It shall be safe  to destroy an initialized condition variable upon which no threads are currently blocked. Attempting to destroy condition variable upon which other threads are currently blocked results in an undefined behavior.
It shall be safe  to destroy an initialized condition variable upon which no threads are currently blocked. Attempting to destroy condition variable upon which other threads are currently blocked results in an undefined behavior.
</p><p>Return Value: If successful the function returns zero; otherwise, an error number is returned to indicate the error.
 
</p><p><br />
Return Value: If successful the function returns zero; otherwise, an error number is returned to indicate the error.
For example<sup id="cite_ref-16" class="reference"><a href="#cite_note-16">[17]</a></sup>, consider the following code:
 
</p><p><code>
For example<ref>http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html#BASICS</ref>, consider the following code:
</p>
 
<pre> struct list  
<code>
{
  struct list  
    pthread_mutex_t lm;
  {
    ...
    pthread_mutex_t lm;
}
    ...
struct elt  
  }
{
  struct elt  
    key k;
  {
    int busy;
    key k;
    pthread_cond_t notbusy;
    int busy;
    ...
    pthread_cond_t notbusy;
}
    ...
/* Find a list element and reserve it. */
  }
struct elt * list_find(struct list *lp, key k)
  /* Find a list element and reserve it. */
{
  struct elt * list_find(struct list *lp, key k)
    struct elt *ep;
  {
      pthread_mutex_lock(&amp;lp-&gt;lm);
    struct elt *ep;
      while ((ep = find_elt(l, k)&#160;!= NULL) &amp;&amp; ep-&gt;busy)
      pthread_mutex_lock(&lp->lm);
      pthread_cond_wait(&amp;ep-&gt;notbusy, &amp;lp-&gt;lm);
      while ((ep = find_elt(l, k) != NULL) && ep->busy)
      if (ep&#160;!= NULL)
      pthread_cond_wait(&ep->notbusy, &lp->lm);
      ep-&gt;busy = 1;
      if (ep != NULL)
      pthread_mutex_unlock(&amp;lp-&gt;lm);
      ep->busy = 1;
      return(ep);
       pthread_mutex_unlock(&lp->lm);
}
       return(ep);
delete_elt(struct list *lp, struct elt *ep)
{
    pthread_mutex_lock(&amp;lp-&gt;lm);
    assert(ep-&gt;busy);
    ... remove ep from list ...
    ep-&gt;busy = 0; /* Paranoid. */
      (A) pthread_cond_broadcast(&amp;ep-&gt;notbusy);
       pthread_mutex_unlock(&amp;lp-&gt;lm);
      (B) pthread_cond_destroy(&amp;rp-&gt;notbusy);
       free(ep);  
   }
   }
</pre>
  delete_elt(struct list *lp, struct elt *ep)
<p></code>
  {
</p><p>In this example, the condition variable and its list element may be freed (line  B) immediately after all threads waiting for it are awakened (line A), since the mutex and the code ensure that no other thread can touch the element to be deleted.
    pthread_mutex_lock(&lp->lm);
</p>
    assert(ep->busy);
<h5><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=20" title="Edit section: Waiting on condition">edit</a>]</span> <span class="mw-headline" id="Waiting_on_condition"> Waiting on condition</span></h5>
    ... remove ep from list ...
<p><b>•  <i>int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);</i> and <i>int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex):</i></b>
    ep->busy = 0; /* Paranoid. */
These functions are used to block a condition variable. They are called with mutex locked by the calling thread or undefined behavior results.These functions atomically release mutex and cause the  calling thread to block on the condition variable cond; atomically here means atomically with respect to access by another thread to the  mutex and then the condition variable. That is, if another thread is able to acquire the mutex after the about-to-block thread has released it, then a subsequent call to pthread_cond_broadcast() or pthread_cond_signal() in that thread shall behave as if it were issued after the about-to-block thread has blocked.The mutex would be locked and be owned by the calling thread upon successful return.
      (A) pthread_cond_broadcast(&ep->notbusy);
</p>
        pthread_mutex_unlock(&lp->lm);
<h5><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=21" title="Edit section: Waking thread based on condition">edit</a>]</span> <span class="mw-headline" id="Waking_thread_based_on_condition"> Waking thread based on condition</span></h5>
      (B) pthread_cond_destroy(&rp->notbusy);
<p><b>•  <i>pthread_cond_broadcast(pthread_cond_t *cond): and pthread_cond_signal(pthread_cond_t *cond):</i></b> These  functions unblock threads blocked on a condition variable.The pthread_cond_broadcast() function unblocks  all threads  currently blocked on the specified condition variable cond. The pthread_cond_signal() function unblocks at least one of the threads that are blocked on the specified condition variable cond (if any threads are blocked on cond).
        free(ep);
</p><p>If  more than one thread  is blocked on a condition variable, the scheduling policy determines the order in which threads are unblocked.When each thread unblocked as a result of a pthread_cond_broadcast() or pthread_cond_signal() returns from its call to pthread_cond_wait() or pthread_cond_timedwait(), the thread owns the mutex with which it called pthread_cond_wait() or pthread_cond_timedwait().The thread(s) that are unblocked contend for the mutex according to the scheduling policy and as if each had called pthread_mutex_lock().
  }
</p>
</code>
<h4><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=22" title="Edit section: Barriers">edit</a>]</span> <span class="mw-headline" id="Barriers">  Barriers  </span></h4>
 
<p>A barrier<sup id="cite_ref-17" class="reference"><a href="#cite_note-17">[18]</a></sup> is a type of synchronization method which is used for a group of threads or processes in the source code. It basically stops any thread/process at a certain point till all other threads/processes reach it. Only then are the processes are allowed to proceed.
In this example, the condition variable and its list element may be freed (line  B) immediately after all threads waiting for it are awakened (line A), since the mutex and the code ensure that no other thread can touch the element to be deleted.
</p>
 
<h5><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=23" title="Edit section: Initialising the Barrier">edit</a>]</span> <span class="mw-headline" id="Initialising_the_Barrier"> Initialising the Barrier</span></h5>
===== Waiting on condition=====
<p><b>•  <i>int pthread_barrier_init(pthread_barrier_t *restrict barrier, const pthread_barrierattr_t *restrict attr, unsigned count):</i></b> The init function initializes the barrier with the specified attributes and reserves any resources required to use the barrier. Attempting to initialize an already initialized barrier or initializing a barrier when any thread is blocked on the barrier or using an uninitialized barrier would lead to undefined results.
These functions are used to block a condition variable.
</p><p>The count argument specified the number of threads that must call before any of the them successfully return from the call and hence it should be a positive number greater than zero.Failure of the init function results in non initialization of the barrier and the contents of barrier are undefined.Only the object referenced by barrier may be used for performing synchronization. The result of referring to copies of that object in calls to pthread_barrier_destroy() or pthread_barrier_wait() is undefined.
 
</p><p>Return Value: Upon successful completion, these functions shall return zero; otherwise, an error number shall be returned to indicate the error.
'''•  ''int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);'' and ''int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex):'''''
</p>
These functions are called with mutex locked by the calling thread or undefined behavior results.They atomically release mutex and cause the  calling thread to block on the condition variable cond; atomically here means atomically with respect to access by another thread to the  mutex and then the condition variable. That is, if another thread is able to acquire the mutex after the about-to-block thread has released it, then a subsequent call to pthread_cond_broadcast() or pthread_cond_signal() in that thread shall behave as if it were issued after the about-to-block thread has blocked.The mutex would be locked and be owned by the calling thread upon successful return.
<h5><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=24" title="Edit section: Barrier Wait">edit</a>]</span> <span class="mw-headline" id="Barrier_Wait"> Barrier Wait </span></h5>
 
<p><b>•  <i>int pthread_barrier_wait(pthread_barrier_t *barrier):</i></b>  The wait function is used to synchronize parallel threads.Until a required number of threads call pthread_barrier_wait() referring the barrier, the calling thread blocks.When the required number of threads call the barrier referenced, a zero value is returned to all the threads, except for one.The constant PTHREAD_BARRIER_SERIAL_THREAD is returned to one unspecified thread.And then it is sent to the state it has as a result of the most recent init function.
===== Waking thread based on condition=====
</p><p>When the required number of threads have arrived at the barrier during the execution of a signal handler, it marks the completion of barrier wait.If a signal is delivered to a thread blocked on a barrier, upon return from the signal handler the thread resumes waiting at the barrier if the barrier wait has not completed; otherwise, the thread continues as normal from the completed barrier wait. Until the thread in the signal handler returns from it, it is unspecified whether other threads may proceed past the barrier once they have all reached it.A thread that has blocked on a barrier does not prevent any unblocked thread that is eligible to use the same processing resources from eventually making forward progress in its execution. Eligibility for processing resources is determined by the scheduling policy.
These  functions unblock threads blocked on a condition variable.
</p><p>Return Value: Upon successful completion, the function shall return <a href="http://www.lindevdoc.org/doku/libc:pthread_barrier_serial_thread" class="external text" rel="nofollow">PTHREAD_BARRIER_SERIAL_THREAD</a> for an arbitrary thread synchronized at the barrier and zero for each of the other threads. Otherwise, an error number shall be returned to indicate the error.
 
</p>
'''•  ''pthread_cond_broadcast(pthread_cond_t *cond): and pthread_cond_signal(pthread_cond_t *cond):''''' The pthread_cond_broadcast() function unblocks  all threads  currently blocked on the specified condition variable cond. The pthread_cond_signal() function unblocks at least one of the threads that are blocked on the specified condition variable cond (if any threads are blocked on cond).
<h5><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=25" title="Edit section: Destroying the Barrier">edit</a>]</span> <span class="mw-headline" id="Destroying_the_Barrier"> Destroying the Barrier </span></h5>
 
<p><b>•  <i>int pthread_barrier_destroy(pthread_barrier_t *barrier):</i></b>This function is used to destroy the barrier passed by the barrier attribute and also releases any resources used by the barrier. A destroyed barrier can be reused when reinitialized by another call to pthread_barrier_init().The destroyed barrier is set to an invalid value. The results are undefined if pthread_barrier_destroy() is called when any thread is blocked on the barrier, or if this function is called with an uninitialized barrier.
If  more than one thread  is blocked on a condition variable, the scheduling policy determines the order in which threads are unblocked.When each thread unblocked as a result of a pthread_cond_broadcast() or pthread_cond_signal() returns from its call to pthread_cond_wait() or pthread_cond_timedwait(), the thread owns the mutex with which it called pthread_cond_wait() or pthread_cond_timedwait().The thread(s) that are unblocked contend for the mutex according to the scheduling policy and as if each had called pthread_mutex_lock().
</p><p>Return Value: Upon successful completion, the functions returns zero; otherwise, an error number is returned to indicate the error.
 
</p>
==== Barriers  ====
<h5><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=26" title="Edit section: Pseudo code">edit</a>]</span> <span class="mw-headline" id="Pseudo_code_3"><b>Pseudo code</b></span></h5>
 
<pre>  <code>
A barrier<ref>http://www.cs.utah.edu/~retrac/papers/jpdc05.pdf</ref> is a type of synchronization method which is used for a group of threads or processes in the source code. It basically stops any thread/process at a certain point till all other threads/processes reach it. Only then are the processes are allowed to proceed.
  pthread_barrier_t *barrier;
 
  pthread_barrierattr_t *attr;
===== Initialising the Barrier=====
  unsigned int count;
 
  int i = pthread_barrier_init(barrier, attr, count);            // initialize the barrier
'''•  ''int pthread_barrier_init(pthread_barrier_t *restrict barrier, const pthread_barrierattr_t *restrict attr, unsigned count):''''' The init function initializes the barrier with the specified attributes and reserves any resources required to use the barrier. Attempting to initialize an already initialized barrier or initializing a barrier when any thread is blocked on the barrier or using an uninitialized barrier would lead to undefined results.
 
  if(i!=0)
The count argument specified the number of threads that must call before any of the them successfully return from the call and hence it should be a positive number greater than zero.Failure of the init function results in non initialization of the barrier and the contents of barrier are undefined.Only the object referenced by barrier may be used for performing synchronization. The result of referring to copies of that object in calls to pthread_barrier_destroy() or pthread_barrier_wait() is undefined.
      printf(“Error occurred barrier was not initialized”):
 
 
Return Value: Upon successful completion, these functions shall return zero; otherwise, an error number shall be returned to indicate the error.
  int b = pthread_barrier_wait(barrier);                          //synchronize participating threads
 
  if(b!=0)
===== Barrier Wait =====
      printf(“Error occurred in synchronizing threads”);
The wait function is used to synchronize parallel threads.
 
 
  /* critical section */
'''•  ''int pthread_barrier_wait(pthread_barrier_t *barrier):''''' Until a required number of threads call pthread_barrier_wait() referring the barrier, the calling thread blocks.When the required number of threads call the barrier referenced, a zero value is returned to all the threads, except for one.The constant PTHREAD_BARRIER_SERIAL_THREAD is returned to one unspecified thread.And then it is sent to the state it has as a result of the most recent init function.
 
 
  int d = pthread_barrier_destroy(barrier);                      //destroy the barrier
When the required number of threads have arrived at the barrier during the execution of a signal handler, it marks the completion of barrier wait.If a signal is delivered to a thread blocked on a barrier, upon return from the signal handler the thread resumes waiting at the barrier if the barrier wait has not completed; otherwise, the thread continues as normal from the completed barrier wait. Until the thread in the signal handler returns from it, it is unspecified whether other threads may proceed past the barrier once they have all reached it.A thread that has blocked on a barrier does not prevent any unblocked thread that is eligible to use the same processing resources from eventually making forward progress in its execution. Eligibility for processing resources is determined by the scheduling policy.
  if(d!=0)
 
      printf(“Error occurred barrier was not destroyed”):
Return Value: Upon successful completion, the function shall return [http://www.lindevdoc.org/doku/libc:pthread_barrier_serial_thread PTHREAD_BARRIER_SERIAL_THREAD] for an arbitrary thread synchronized at the barrier and zero for each of the other threads. Otherwise, an error number shall be returned to indicate the error.
  </code>
 
</pre>
===== Destroying the Barrier =====
<h2><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=27" title="Edit section: References">edit</a>]</span> <span class="mw-headline" id="References"> References </span></h2>
 
<ol class="references"><li id="cite_note-0"><a href="#cite_ref-0">↑</a> Rahman, M.M.; , "Process synchronization in multiprocessor and multi-core processor," Informatics, Electronics &amp; Vision (ICIEV), 2012 International Conference on , vol., no., pp.554-559, 18-19 May 2012</li>
'''•  ''int pthread_barrier_destroy(pthread_barrier_t *barrier):'''''This function is used to destroy the barrier passed by the barrier attribute and also releases any resources used by the barrier. A destroyed barrier can be reused when reinitialized by another call to pthread_barrier_init().The destroyed barrier is set to an invalid value. The results are undefined if pthread_barrier_destroy() is called when any thread is blocked on the barrier, or if this function is called with an uninitialized barrier.
<li id="cite_note-1"><a href="#cite_ref-1">↑</a> <a href="http://people.csail.mit.edu/rinard/paper/cpande99.pdf" class="external free" rel="nofollow">http://people.csail.mit.edu/rinard/paper/cpande99.pdf</a></li>
 
<li id="cite_note-2"><a href="#cite_ref-2">↑</a> <a href="http://linux.die.net/man/3/" class="external free" rel="nofollow">http://linux.die.net/man/3/</a></li>
Return Value: Upon successful completion, the functions returns zero; otherwise, an error number is returned to indicate the error.
<li id="cite_note-3"><a href="#cite_ref-3">↑</a> <a href="http://www-numi.fnal.gov/computing/minossoft/releases/R2.3/WebDocs/Errors/unix_system_errors.html" class="external free" rel="nofollow">http://www-numi.fnal.gov/computing/minossoft/releases/R2.3/WebDocs/Errors/unix_system_errors.html</a></li>
 
<li id="cite_note-4"><a href="#cite_ref-4">↑</a> <a href="http://pubs.opengroup.org/onlinepubs/7908799/xsh/errors.html" class="external free" rel="nofollow">http://pubs.opengroup.org/onlinepubs/7908799/xsh/errors.html</a></li>
====='''Pseudocode'''=====
<li id="cite_note-5"><a href="#cite_ref-5">↑</a> <a href="http://www.kernel.org/doc/man-pages/online/pages/man3/errno.3.html" class="external free" rel="nofollow">http://www.kernel.org/doc/man-pages/online/pages/man3/errno.3.html</a></li>
    <code>
<li id="cite_note-6"><a href="#cite_ref-6">↑</a> <a href="http://maxim.int.ru/bookshelf/PthreadsProgram/toc.html" class="external free" rel="nofollow">http://maxim.int.ru/bookshelf/PthreadsProgram/toc.html</a></li>
    pthread_barrier_t *barrier;
<li id="cite_note-7"><a href="#cite_ref-7">↑</a> <a href="http://docs.oracle.com/cd/E19963-01/html/821-1601/sync-28983.html" class="external free" rel="nofollow">http://docs.oracle.com/cd/E19963-01/html/821-1601/sync-28983.html</a></li>
    pthread_barrierattr_t *attr;
<li id="cite_note-8"><a href="#cite_ref-8">↑</a> Raghunathan, S.; , "Extending Inter-process Synchronization with Robust Mutex and Variants in Condition Wait," Parallel and Distributed Systems, 2008. ICPADS '08. 14th IEEE International Conference on , vol., no., pp.121-128, 8-10 Dec. 2008</li>
    unsigned int count;
<li id="cite_note-9"><a href="#cite_ref-9">↑</a> <a href="http://pic.dhe.ibm.com/infocenter/aix/v7r1/index.jsp?topic=%2Fcom.ibm.aix.genprogc%2Fdoc%2Fgenprogc%2Fmutexes.htm" class="external free" rel="nofollow">http://pic.dhe.ibm.com/infocenter/aix/v7r1/index.jsp?topic=%2Fcom.ibm.aix.genprogc%2Fdoc%2Fgenprogc%2Fmutexes.htm</a></li>
    int i = pthread_barrier_init(barrier, attr, count);            // initialize the barrier
<li id="cite_note-10"><a href="#cite_ref-10">↑</a> <a href="http://developer.apple.com/library/ios/#documentation/System/Conceptual/ManPages_iPhoneOS/man3/pthread_mutexattr_settype.3.html" class="external free" rel="nofollow">http://developer.apple.com/library/ios/#documentation/System/Conceptual/ManPages_iPhoneOS/man3/pthread_mutexattr_settype.3.html</a></li>
   
<li id="cite_note-11"><a href="#cite_ref-11">↑</a> <a href="http://www2.chrishardick.com:1099/Notes/Computing/C/pthreads/mutexes.html" class="external free" rel="nofollow">http://www2.chrishardick.com:1099/Notes/Computing/C/pthreads/mutexes.html</a></li>
    if(i!=0)
<li id="cite_note-12"><a href="#cite_ref-12">↑</a> <a href="http://pages.cs.wisc.edu/~remzi/Classes/537/Fall2011/Book/threads-deadlock.pdf" class="external free" rel="nofollow">http://pages.cs.wisc.edu/~remzi/Classes/537/Fall2011/Book/threads-deadlock.pdf</a></li>
      printf(“Error occurred barrier was not initialized”):
<li id="cite_note-13"><a href="#cite_ref-13">↑</a> <a href="http://software.intel.com/sites/products/documentation/doclib/stdxe/2013/inspectorxe/lin/ug_docs/GUID-38B68BDA-257C-4D4E-9AC9-B0B2698AD950.htm" class="external free" rel="nofollow">http://software.intel.com/sites/products/documentation/doclib/stdxe/2013/inspectorxe/lin/ug_docs/GUID-38B68BDA-257C-4D4E-9AC9-B0B2698AD950.htm</a></li>
   
<li id="cite_note-14"><a href="#cite_ref-14">↑</a> <a href="http://docs.oracle.com/cd/E19683-01/806-6867/sync-36993/index.html" class="external free" rel="nofollow">http://docs.oracle.com/cd/E19683-01/806-6867/sync-36993/index.html</a></li>
    int b = pthread_barrier_wait(barrier);                          //synchronize participating threads
<li id="cite_note-15"><a href="#cite_ref-15">↑</a> <a href="http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp" class="external free" rel="nofollow">http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp</a></li>
    if(b!=0)
<li id="cite_note-16"><a href="#cite_ref-16">↑</a> <a href="http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html#BASICS" class="external free" rel="nofollow">http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html#BASICS</a></li>
      printf(“Error occurred in synchronizing threads”);
<li id="cite_note-17"><a href="#cite_ref-17">↑</a> <a href="http://www.cs.utah.edu/~retrac/papers/jpdc05.pdf" class="external free" rel="nofollow">http://www.cs.utah.edu/~retrac/papers/jpdc05.pdf</a></li></ol>
   
<h2><span class="editsection">[<a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;section=28" title="Edit section: Quiz">edit</a>]</span> <span class="mw-headline" id="Quiz"> Quiz </span></h2>
    /* critical section */
<p>1. What happens if a semaphore cannot be acquired?(More than one options could be correct)
   
</p><p>a. The process is woken up.
    int d = pthread_barrier_destroy(barrier);                      //destroy the barrier
</p><p>b. The process cache is saved off and can be retrieved when the process is woken up.
    if(d!=0)
</p><p>c. The process is put to sleep.
      printf(“Error occurred barrier was not destroyed”):
</p><p>d. The process proceeds into the critical section.
    </code>
</p><p><br />
 
2. Which one of the following attempts is valid?
== Synchronization Mechanisms Examples ==
</p><p>a. Multiple simultaneous calls to pthread_join using the same target.
 
</p><p>b. Initializing an already initialized conditional variable.
DOALL parallelism is supported by parallelization mechanisms like semaphore, mutex, condition variable and barrier depending on applications.
</p><p>c. Initializing an already destroyed mutex.
DOACROSS and DOPIPE parallelism are supported by point to point synchronization mechanisms like semaphore and mutex.
</p><p>d. Destroying a locked mutex
 
</p><p><br />
=== DOALL Parallelism ===
3. Upon successful completion what does an int pthread_barrier_wait(pthread_barrier_t *barrier) function return?(More than one options could be correct)         
-----------------------
</p><p>a. Zero for all the threads.
 
</p><p>b. PTHREAD_BARRIER_SERIAL_THREAD for an arbitrary thread synchronized at the barrier.
Consider the following code, amenable to DOALL parallelism.
</p><p>c. Zero for each of the threads,except for one.
 
</p><p>d. None of the above.
'''Code Segment'''
</p><p><br />
    for ( i = 1 ; i <= N ; i++ )
4. Which of the following functions are used to lock a semaphore?(More than one options could be correct)
    {
</p><p>a. sem_post
        S1: a[i] = b[i] + c[i];      /* can be parallelized */
</p><p>b. sem_wait
        S2: sum  = sum + a[i] ;      /* critical section that must be protected by synchronization mechanism */
</p><p>c. sem_trywait
    }
</p><p>d. sem_timedwait
 
</p><p><br />
There are no loop dependencies for S1 and S2, but we can see that "sum" is a critical variable.
5. What parameters does the method pthread_join() take? (More than one options could be correct)
"sum" can be protected using various synchronization mechanisms like semaphores, mutexes and condition variables. They are illustrated as follows.
</p><p>a. Null
 
</p><p>b. value_ptr
'''Semaphore Pseudocode'''
</p><p>c. thread_id
 
</p><p>d. value passed from pthread exit
    sem_t * sem;
</p><p><br />
    sem_init ( sem , 0 , 1 );        /*initialize the semaphore variable*/
6.  Which of the following is true about mutexes and semaphores?
    for ( i =1 ; i <= N ; i++ )      /*parallelize the for loop*/
</p><p>a. Both semaphore and mutexes are used to prevent multiple threads from operating on a single memory location.
    {     
</p><p>b. Mutexes work between processes and semaphores work only between threads of a single process.
            a[i] = b[i] + c[i];
</p><p>c. Mutexes work only between threads in a process and semaphores work between processes.
            sem_wait(sem);          /*enter critical section if sem ==0*/
</p><p>d. None of the above.
            sum  = sum + a[i] ;
</p><p><br />
            sem_post(sem);          /*exit critical section*/
7. Which of the following functions would unlock threads blocked on a conditional variable?(More than one options could be correct)
    }
</p><p>a. int pthread_cond_timedwait
 
</p><p>b. int pthread_cond_init
Even though semaphore achieves the objective of protecting the critical section, mutex provides additional security by preventing accidental deletion of locks. This property is due to the exclusive ownership property associated with mutex variables where only the locked mutex can unlock the critical section.
</p><p>c. pthread_cond_broadcast
 
</p><p>d. pthread_cond_signal
'''Mutex Pseudocode'''
</p><p><br />
8. What is the significance of <i>abs_timeout</i> in sem_timedwait function?
    pthread_mutext * mut_id;
</p><p>a. It specifies to return an error if immediate decrement cannot be performed.
    pthread_mutex_init (mut_id);            /*initialize mutex variable */
</p><p>b. It specifies a limit on the amount of time that the call should block.
    for ( i =1 ; i <= N ; i++ )              /* parallelize the for loop */
</p><p>c. It specifies a timeout error.
    {   
</p><p>d. None of the above
            a[i] = b[i] + c[i];
</p><p><br />
            pthread_mutex_lock ( mut_id );  /* enter critical section if mut_id is free*/
9. Which of the following type of mutexes maintain a lock count?
            sum = sum + a[i];
</p><p>a. ERRORCHECK
            pthread_mutex_unlock ( mut_id ); /*exit critical section*/
</p><p>b. DEFAULT
    }
</p><p>c. RECURSIVE
 
</p><p>d. INITIALIZER
Suppose in the above example the thread has to wait for some other arbitrary process to complete in the critical section, then conditional variable synchronization can be used. Here the mutex will wait until a condition variable is satisfied. The setting of a condition variable is controlled by other another thread. This is illustrated as follows.
</p><p><br />
 
10. When a mutex is initialized with NULL attributes
'''Conditional Variable Pseudocode'''
</p><p>a. Error is returned
 
</p><p>b. The mutex referenced is not initialized.
    //thread 1: main thread
</p><p>c. Default mutex attributes are used to initialize the mutex.
    pthread_condition_t * cond;
</p><p>d. The referenced mutex is destroyed.
    pthread_mutex_init ( mut_id );
</p>
    for ( i =1 ; i <= N ; i++ ) // parallelize the for loop
<!--
    {
NewPP limit report
        a[i] = b[i] + c[i];
Preprocessor node count: 443/1000000
        pthread_mutex_lock ( mut_id );  /*enter critical section if mut_id is free*/
Post-expand include size: 0/2097152 bytes
        sum = sum + a[i];
Template argument size: 0/2097152 bytes
        pthread_cond_wait(cond,mut_id);  /*this thread goes to sleep until ‘cond’ condition is satisfied*/
Expensive parser function count: 0/100
        pthread_mutex_unlock ( mut_id ); /*exit critical section*/
-->
    }
    //thread 2: condition signaling
    while (i > 0)
    i -- ;
    if (i == 0)
    { pthread_mutex_lock (mut_id);      /* mut_id indicates thread 1 mutex is targeted by this condition */
        pthread_cond_signal (cond,mut_id); /* set condition variable*/
        pthread_mutex_unlock ( mut_id );  /* exit mutex*/
    }
 
The previous example does not mandate barrier synchronization, as the purpose was to avoid shared memory read contention. The purpose of barrier synchronization is to address the case when one needs to complete all parallel tasks until a common point before proceeding. Consider the following code, amenable to DOALL parallelism, slightly modified for illustrating barrier synchronization.
 
    for ( i = 1 ; i <= N ; i++ )
    {
        a[i] = b[i] + c[i] ;
        min(a);               /*computes the minimum value from array a*/
    }
 
In the above example, minimum of "a" can be calculated only after the computations for "a" is complete. The Barrier implementation for the above code segment is shown below:
 
'''Barrier Pseudocode'''
 
    pthread_barrier_t* bar;
    pthread_barrier_init (bar, attr, nthreads); /*initialize barrier variable*/
    for ( i=1 ; i <= N ; i++ )                  /* parallelize the for loop*/
    { 
        a[i] = b[i] + c[i];
        pthread_barrier_wait (bar);            /* Post the barrier*/
min(a);                                 /*computes the minimum value from array a */
    }
 
=== DOACROSS Parallelism ===
-----------------------
 
Consider the following code, amenable to DOACROSS parallelism
 
    for ( i = 1 ; i <= N ; i++ )
    {
        S1: d[i] = b[i] * c[i] ;  /*no loop dependencies*/
        S2: a[i] = a[i-1] + d[i]; /* loop dependency present*/
    }
 
S1 does not have any inter loop dependencies. However, S2 is dependent on S1, and S2 has inter loop dependencies. Thus we can parallelize S1 without any synchronization. However, we need synchronization mechanisms for S2. The above code can be parallelized using semaphores and mutexes. The advantages of using mutex over semaphore is the same as mentioned before in DOALL parallelism. They are illustrated as follows.


<!-- Saved in parser cache with key pg_wiki:pcache:idhash:5276-0!*!0!!en!* and timestamp 20140225193649 -->
'''Semaphore Pseudocode'''
<div class="printfooter">
Retrieved from "<a href="http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_506_Spring_2013/3a_bs">http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_506_Spring_2013/3a_bs</a>"</div>
<!-- /bodytext -->
<!-- catlinks -->
<div id='catlinks' class='catlinks catlinks-allhidden'></div> <!-- /catlinks -->
<div class="visualClear"></div>
</div>
<!-- /bodyContent -->
</div>
<!-- /content -->
<!-- header -->
<div id="mw-head" class="noprint">
<!-- 0 -->
<div id="p-personal" class="">
<h5>Personal tools</h5>
<ul>
<li  id="pt-userpage"><a href="/index.php/User:Sviyer4" title="Your user page [.]" accesskey="." class="new">Sviyer4</a></li>
<li  id="pt-mytalk"><a href="/index.php/User_talk:Sviyer4" title="Your talk page [n]" accesskey="n" class="new">My talk</a></li>
<li  id="pt-preferences"><a href="/index.php/Special:Preferences" title="Your preferences">My preferences</a></li>
<li  id="pt-watchlist"><a href="/index.php/Special:Watchlist" title="The list of pages you are monitoring for changes [l]" accesskey="l">My watchlist</a></li>
<li  id="pt-mycontris"><a href="/index.php/Special:Contributions/Sviyer4" title="List of your contributions [y]" accesskey="y">My contributions</a></li>
<li  id="pt-logout"><a href="/index.php?title=Special:UserLogout&amp;returnto=CSC/ECE_506_Spring_2013/3a_bs" title="Log out">Log out</a></li>
</ul>
</div>


<!-- /0 -->
    sem_t * sem;                    /* a vector of semaphores used to keep track of each loop */
<div id="left-navigation">
    for ( i =1 ; i <= N ; i++ )
    {
<!-- 0 -->
        sem_init( sem[i], 0 ,1); /* one semaphore initialized for each iteration */
<div id="p-namespaces" class="vectorTabs">
        S1: d[i] = b[i] * c[i]/* no dependencies, hence parallel execution */
<h5>Namespaces</h5>
        sem_wait( sem[i-1]);
<ul>
        S2: a[i] = a[i-1] + d[i]; /*executes only if S2 in previous loop completes execution*/
<li id="ca-nstab-main" class="selected"><span><a href="/index.php/CSC/ECE_506_Spring_2013/3a_bs"  title="View the content page [c]" accesskey="c">Page</a></span></li>
        sem_post(sem[i]);
<li  id="ca-talk" class="new"><span><a href="/index.php?title=Talk:CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit&amp;redlink=1"  title="Discussion about the content page [t]" accesskey="t">Discussion</a></span></li>
    }
</ul>
</div>


<!-- /0 -->
'''Mutex Pseudocode'''


<!-- 1 -->
    pthread_mutext * mut_id;// a vector of semaphores of length N is  used
<div id="p-variants" class="vectorMenu emptyPortlet">
    for ( i =1 ; i <= N ; i++ )
<h5><span>Variants</span><a href="#"></a></h5>
    {
<div class="menu">
        pthread_mutex_init (mut_id[i]);      /*one mutex initialized for each iteration*/
<ul>
        S1: d[i] = b[i] * c[i];
</ul>
        pthread_mutex_lock ( mut_id [i-1] ); /* no dependencies, hence parallel execution*/
</div>
        S2: a[i] = a[i-1] +d[i];            /*executes only if S2 in previous loop completes execution*/
</div>
        pthread_mutex_unlock ( mut_id [i]);
    }


<!-- /1 -->
===  DOPIPE Parallelism ===
</div>
-----------------------
<div id="right-navigation">
<!-- 0 -->
<div id="p-views" class="vectorTabs">
<h5>Views</h5>
<ul>
<li id="ca-view" class="selected"><span><a href="/index.php/CSC/ECE_506_Spring_2013/3a_bs" >Read</a></span></li>
<li id="ca-edit"><span><a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=edit"  title="You can edit this page. Please use the preview button before saving [e]" accesskey="e">Edit</a></span></li>
<li id="ca-history" class="collapsible "><span><a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=history"  title="Past revisions of this page [h]" accesskey="h">View history</a></span></li>
</ul>
</div>


<!-- /0 -->
Consider the following code, amenable to DOPIPE parallelism


<!-- 1 -->
    for ( i = 1 ; i <= N ; i++ )
<div id="p-cactions" class="vectorMenu">
    {
<h5><span>Actions</span><a href="#"></a></h5>
        S1: a[i] = a[i-1] + b[i] ; /* loop dependent statement */
<div class="menu">
        S2: c[i] = c[i] + a[i];    /* loop independent but dependent on S1 */
<ul>
    }
<li id="ca-move"><a href="/index.php/Special:MovePage/CSC/ECE_506_Spring_2013/3a_bs"  title="Move this page [m]" accesskey="m">Move</a></li>
<li id="ca-watch"><a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;action=watch"  title="Add this page to your watchlist [w]" accesskey="w">Watch</a></li>
</ul>
</div>
</div>


<!-- /1 -->
S1 has inter loop dependencies. S2 depends on S1 even though S2 does not have loop dependencies. Hence S2 can be executed only after S1 is executed in each loop. This necessitates the use of synchronization mechanisms.
The above code can be parallelized using semaphores and mutexes. They are illustrated as follows.


<!-- 2 -->
'''Semaphore Pseudodode'''
<div id="p-search">
<h5><label for="searchInput">Search</label></h5>
<form action="/index.php" id="searchform">
<input type='hidden' name="title" value="Special:Search"/>
<input id="searchInput" name="search" type="text"  title="Search PG_Wiki [f]" accesskey="f"  value="" />
<input type='submit' name="go" class="searchButton" id="searchGoButton" value="Go" title="Go to a page with this exact name if exists" />
<input type="submit" name="fulltext" class="searchButton" id="mw-searchButton" value="Search" title="Search the pages for this text" />
</form>
</div>


<!-- /2 -->
    sem_t * sem;
</div>
    for ( i = 1 ; i <= N ; i++ )
</div>
    {
<!-- /header -->
        sem_init(sem[i] , 0 ,1);   /*initialize all N semaphore variables*/
<!-- panel -->
    }
<div id="mw-panel" class="noprint">
    for ( i = 1 ; i <= N ; i++ )
<!-- logo -->
    {
<div id="p-logo"><a style="background-image: url(/skins/common/images/expertiza_logo.png);" href="/index.php/Main_Page"  title="Visit the main page"></a></div>
        S1: a[i] = a[i-1] + b[i] ; /*loop dependent statement executed first*/
<!-- /logo -->
        sem_post (sem[i]);        /*Tell second loop that S1 is completed*/
    }
<!-- navigation -->
    for ( i = 1 ; i <= N ; i++ )
<div class="portal" id='p-navigation'>
    {
<h5>Navigation</h5>
        sem_wait(sem[i]);          /*Wait for S1 to complete in first loop*/
<div class="body">
        S2: c[i] = c[i] + a[i] /*Execute once synchronization is done*/
<ul>
    }
<li id="n-mainpage-description"><a href="/index.php/Main_Page" title="Visit the main page [z]" accesskey="z">Main page</a></li>
<li id="n-portal"><a href="/index.php/PG_Wiki:Community_portal" title="About the project, what you can do, where to find things">Community portal</a></li>
<li id="n-currentevents"><a href="/index.php/PG_Wiki:Current_events" title="Find background information on current events">Current events</a></li>
<li id="n-recentchanges"><a href="/index.php/Special:RecentChanges" title="The list of recent changes in the wiki [r]" accesskey="r">Recent changes</a></li>
<li id="n-randompage"><a href="/index.php/Special:Random" title="Load a random page [x]" accesskey="x">Random page</a></li>
<li id="n-help"><a href="/index.php/Help:Contents" title="The place to find out">Help</a></li>
</ul>
</div>
</div>


<!-- /navigation -->
'''Mutex Pseudocode'''


<!-- SEARCH -->
    pthread_mutex_t * mut_id;
    for ( i = 1 ; i <= N ; i++ )
    {
        pthread_mutex_init(mut_id[i]); /*initialize all mutex variables*/
    }
    for ( i = 1 ; i <= N ; i++ )
    {
        S1: a[i] = a[i-1] + b[i] ;        /*loop dependent statement executed first*/
        pthread_mutex_unlock (mut_id[i]); /*Tell second loop that S1 is completed*/
    }
    for ( i = 1 ; i <= N ; i++ )
    {
        pthread_mutex_lock (mut_id[i]);  /*Wait for S1 to complete in first loop */
        S2: c[i] = c[i] + a[i];          /*Execute once synchronization is done */
    }


<!-- /SEARCH -->
== References ==


<!-- TOOLBOX -->
<References>http://linux.die.net/man/3/
<div class="portal" id="p-tb">
<h5>Toolbox</h5>
<div class="body">
<ul>
<li id="t-whatlinkshere"><a href="/index.php/Special:WhatLinksHere/CSC/ECE_506_Spring_2013/3a_bs" title="List of all wiki pages that link here [j]" accesskey="j">What links here</a></li>
<li id="t-recentchangeslinked"><a href="/index.php/Special:RecentChangesLinked/CSC/ECE_506_Spring_2013/3a_bs" title="Recent changes in pages linked from this page [k]" accesskey="k">Related changes</a></li>
<li id="t-upload"><a href="/index.php/Special:Upload" title="Upload files [u]" accesskey="u">Upload file</a></li>
<li id="t-specialpages"><a href="/index.php/Special:SpecialPages" title="List of all special pages [q]" accesskey="q">Special pages</a></li>
<li id="t-print"><a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;printable=yes" rel="alternate" title="Printable version of this page [p]" accesskey="p">Printable version</a></li>
<li id="t-permalink"><a href="/index.php?title=CSC/ECE_506_Spring_2013/3a_bs&amp;oldid=73526" title="Permanent link to this revision of the page">Permanent link</a></li>
</ul>
</div>
</div>


<!-- /TOOLBOX -->
http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp


<!-- LANGUAGES -->
http://maxim.int.ru/bookshelf/PthreadsProgram/toc.html


<!-- /LANGUAGES -->
http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html#BASICS
</div>
<!-- /panel -->
<!-- footer -->
<div id="footer">
<ul id="footer-info">
<li id="footer-info-lastmod"> This page was last modified on 21 February 2013, at 03:02.</li>
<li id="footer-info-viewcount">This page has been accessed 596 times.</li>
</ul>
<ul id="footer-places">
<li id="footer-places-privacy"><a href="/index.php/PG_Wiki:Privacy_policy" title="PG Wiki:Privacy policy">Privacy policy</a></li>
<li id="footer-places-about"><a href="/index.php/PG_Wiki:About" title="PG Wiki:About">About PG_Wiki</a></li>
<li id="footer-places-disclaimer"><a href="/index.php/PG_Wiki:General_disclaimer" title="PG Wiki:General disclaimer">Disclaimers</a></li>
</ul>
<ul id="footer-icons" class="noprint">
<li id="footer-poweredbyico">
<a href="http://www.mediawiki.org/"><img src="/skins/common/images/poweredby_mediawiki_88x31.png" alt="Powered by MediaWiki" width="88" height="31" /></a>
</li>
</ul>
<div style="clear:both"></div>
</div>
<!-- /footer -->
<script src="/load.php?debug=false&amp;lang=en&amp;modules=startup&amp;only=scripts&amp;skin=vector&amp;*"></script>
<script>if ( window.mediaWiki ) {
mediaWiki.config.set({"wgCanonicalNamespace": "", "wgCanonicalSpecialPageName": false, "wgNamespaceNumber": 0, "wgPageName": "CSC/ECE_506_Spring_2013/3a_bs", "wgTitle": "CSC/ECE 506 Spring 2013/3a bs", "wgAction": "view", "wgArticleId": 5276, "wgIsArticle": true, "wgUserName": "Sviyer4", "wgUserGroups": ["*", "user", "autoconfirmed"], "wgCurRevisionId": 73526, "wgCategories": [], "wgBreakFrames": false, "wgRestrictionEdit": [], "wgRestrictionMove": []});
}
</script>
<script>if ( window.mediaWiki ) {
mediaWiki.loader.load(["mediawiki.util", "mediawiki.legacy.wikibits", "mediawiki.legacy.ajax", "mediawiki.legacy.ajaxwatch"]);
mediaWiki.loader.go();
}
</script>


<script>if ( window.mediaWiki ) {
</References>
mediaWiki.user.options.set({"ccmeonemails":0,"cols":80,"contextchars":50,"contextlines":5,"date":"default","diffonly":0,"disablemail":0,"disablesuggest":0,"editfont":"default","editondblclick":0,"editsection":1,"editsectiononrightclick":0,"enotifminoredits":0,"enotifrevealaddr":0,"enotifusertalkpages":1,"enotifwatchlistpages":0,"extendwatchlist":0,"externaldiff":0,"externaleditor":0,"fancysig":0,"forceeditsummary":0,"gender":"unknown","hideminor":0,"hidepatrolled":0,"highlightbroken":1,"imagesize":2,"justify":0,"math":1,"minordefault":0,"newpageshidepatrolled":0,"nocache":0,"noconvertlink":0,"norollbackdiff":0,"numberheadings":0,"previewonfirst":0,"previewontop":1,"quickbar":1,"rcdays":7,"rclimit":50,"rememberpassword":0,"rows":25,"searchlimit":20,"showhiddencats":0,"showjumplinks":1,"shownumberswatching":1,"showtoc":1,"showtoolbar":1,"skin":"vector","stubthreshold":0,"thumbsize":2,"underline":2,"uselivepreview":0,"usenewrc":0,"watchcreations":0,"watchdefault":0,"watchdeletion":0,
"watchlistdays":3,"watchlisthideanons":0,"watchlisthidebots":0,"watchlisthideliu":0,"watchlisthideminor":0,"watchlisthideown":0,"watchlisthidepatrolled":0,"watchmoves":0,"wllimit":250,"variant":"en","language":"en","searchNs0":true,"searchNs1":false,"searchNs2":false,"searchNs3":false,"searchNs4":false,"searchNs5":false,"searchNs6":false,"searchNs7":false,"searchNs8":false,"searchNs9":false,"searchNs10":false,"searchNs11":false,"searchNs12":false,"searchNs13":false,"searchNs14":false,"searchNs15":false});;mediaWiki.loader.state({"user.options":"ready"});
}
</script> <!-- fixalpha -->
<script type="text/javascript"> if ( window.isMSIE55 ) fixalpha(); </script>
<!-- /fixalpha -->
<!-- Served in 0.146 secs. --> </body>
</html>

Latest revision as of 18:19, 26 April 2014

Problem Statement 3a

Previous Work

Current Work

Overview

The aim of this wiki is to highlight the synchronization mechanisms for DOALL, DOACROSS and DOPIPE parallelization techniques.

Synchronization

Necessity


When using any parallel programming model, synchronization<ref>Rahman, M.M.; , "Process synchronization in multiprocessor and multi-core processor," Informatics, Electronics & Vision (ICIEV), 2012 International Conference on , vol., no., pp.554-559, 18-19 May 2012</ref> is needed to guarantee accuracy of the overall program. The following situations highlight the necessity of synchronization<ref>http://people.csail.mit.edu/rinard/paper/cpande99.pdf</ref>.

Case 1: A scenario in which the code following a parallelized loop requires that all of the parallel processes be completed before advancing.

Case 2: A scenario in which a code segment in the middle of a parallelized section needs to be executed sequentially (critical section), to ensure program correctness.

Case 3: A scenario in which multiple processes must update a global variable in such a way that one process does not overwrite the updates of a different process.

Synchronization Mechanisms


Let us now briefly understand the various process/thread synchronization mechanisms that helps in achieving correct program execution order.

Semaphore: Semaphore is a variable that helps in controlling the access to a common resource in a parallel programming model. Not only do they arbitrate, but also help in avoiding race conditions. Semaphores keep only the count of the resource availability.

Mutex / Lock: Mutex refers to Mutual Exclusion. It helps avoiding concurrency issues like race conditions by ensuring that no two concurrently executed processes access a critical section at the same time. Though Mutexes are essentially the same as Semaphores, the fundamental differences between them are as follows [1]:

1. Mutexes allow exclusive process access to a resource. Semaphores allow any process to access a resource. Thus the element of ownership in mutex ensures that only the process that has locked the mutex can unlock it. However, in case of Semaphores, the process locking and unlocking the semaphore can be different.

2. Mutexes support priority inversion, helping promote the current priority of the process that has the lock, in case a higher priority process starts waiting on the locked mutex.

3. Mutexes, unlike Semaphores ensure that the process holding the mutex cannot be accidentally deleted by other processes.

Conditional Variables: Though the use of Mutex protects an operation, it doesn’t permit the thread to wait until another thread completes an arbitrary activity (e.g. Parent thread might want to wait until the child thread has completed its execution) [2]. By giving this facility, conditional variables help in solving various synchronization problems like the producer/consumer problem [3].

Barriers [4] : This form of synchronization introduces a common stop point for multiple threads and processes. It ensures that all threads/processes reach this barrier before continuing any further.

Case 1, mentioned in the previous subsection, can be addressed using Barrier synchronization. Cases 2 and 3 can be addressed using Semaphores, Mutexes and Conditional Variables.

The following section discusses two libraries that implement the aforementioned synchronization mechanisms.

Libraries<ref>http://linux.die.net/man/3/</ref>

1. Semaphore.h


A semaphore is special variable that acts similar to a lock. For a process to enter into the critical section it must be able to acquire the semaphore. If the semaphore cannot be acquired, then the process is “put to sleep” and the processor is then used for another process. This means the processes cache is saved off in a place where it can be retrieved when the process is “woken up”. Once the semaphore is available the “sleeping” process is woken up and obtains the semaphore and proceeds in to the critical section.A simple way to execute a semaphore would be to use the following functions for various operations on semaphores;

Initializing a semaphore

int sem_init(sem_t *sem, int pshared, unsigned int value): This function initializes the unnamed semaphore at the address pointed to by sem. Value is the initial value of the semaphore. The variable pshared is indicative of whether the semaphore is shared between threads or processes. If its value is zero it is shared between threads else it is shared between processes.

Return Value: sem_init() returns 0 on success; on error, -1 is returned, and errno is set to indicate the error.

Locking the semaphore

By acquiring a lock, it is ensured that the execution of other processes or threads (trying to access the shared resource) is postponed indefinitely. Blocking the execution of a higher priority thread or a thread responsible for performing real time operations may be undesired, thus highlighting the necessity of Non-Blocking statements. Depending upon the application, we may want a blocking or non blocking assignment of locks. This is achieved using the following constructs:

int sem_wait(sem_t *sem):[Blocking] This function decrements (locks) the semaphore pointed to by sem. Decrement will only proceed if the value of the semaphore is greater than zero. If its value is zero, then the call blocks till the value of the semaphore becomes positive so that it can acquire it or a signal handler interrupts the call.

int sem_trywait(sem_t *sem):[Non-Blocking] This function is the same as sem_wait(), except that if the decrement cannot be immediately performed, then call returns an error (errno set to EAGAIN<ref>http://www-numi.fnal.gov/computing/minossoft/releases/R2.3/WebDocs/Errors/unix_system_errors.html</ref>) instead of blocking.

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout):[Blocking with Timeout] This function is also the same as sem_wait(), except that abs_timeout specifies a limit on the amount of time that the call should block if the decrement cannot be immediately performed. The abs_timeout argument points to a structure that specifies an absolute timeout in seconds and nanoseconds. This structure is defined as follows:

      struct timespec 
      {
      time_t tv_sec;          /* Seconds */
      long   tv_nsec;         /* Nanoseconds [0 .. 999999999] */
      };

If the timeout has already expired by the time of the call, and the semaphore could not be locked immediately, then sem_timedwait() fails with a timeout error (errno set to ETIMEDOUT<ref>http://pubs.opengroup.org/onlinepubs/7908799/xsh/errors.html</ref>). If the operation can be performed immediately, then sem_timedwait() never fails with a timeout error, regardless of the value of abs_timeout. Furthermore, the validity of abs_timeout is not checked in this case.

Return Value: All of these functions return 0 on success; on error, the value of the semaphore is left unchanged, -1 is returned, and errno<ref>http://www.kernel.org/doc/man-pages/online/pages/man3/errno.3.html</ref> is set to indicate the error.

Releasing the semaphore

int sem_post(sem_t *sem): This function increments (unlocks) the semaphore pointed to by sem, thus making the value of the semaphore positive. Some other process can now acquire it.

Return Value: sem_post() returns 0 on success; on error, the value of the semaphore is left unchanged, -1 is returned, and errno is set to indicate the error.

Pseudocode

     
     sem_t *sem; 
     int pshared;
     unsigned int value;
     int i = sem_init(sem, pshared, value);                            /*initialize the semaphore*/
     int wait=sem_wait(sem);                                           /*will decrement the value of the semaphore i.e. acquire the lock */
     
     if(wait==-1)
         printf(“Error occurred, the value of the semaphore was not decremented”);
     
     /*critical section;*/
     int post=sem_post(sem);                                           /*will increment the value of the semaphore i.e. release the lock*/
     if(post==-1)
         printf(“Error occurred, the value of the semaphore was not incremented”);
     

2. Pthread.h


POSIX threads<ref>http://maxim.int.ru/bookshelf/PthreadsProgram/toc.html</ref>, usually referred to as pthreads defines a set of programming language types,functions and constants.It is implemented with a pthread.h header file and a thread library. The pthread library provides the following synchronization mechanisms:

1. Mutexes

2. Joins

3. Conditional Variables

4. Barriers

Mutexes

Mutual Exclusion Lock<ref>http://docs.oracle.com/cd/E19963-01/html/821-1601/sync-28983.html</ref>, mutex in short is another synchronization method and is used to avoid race conditions. In cases leading to data inconsistencies,like when multiple threads are to be prevented from operating on the same memory location simultaneously or when a specific order of operation is expected, mutexes are used.It blocks access to variables by other threads. Mutexes are in particular used to protect a critical region (“a segment of memory”) from other threads<ref>Raghunathan, S.; , "Extending Inter-process Synchronization with Robust Mutex and Variants in Condition Wait," Parallel and Distributed Systems, 2008. ICPADS '08. 14th IEEE International Conference on , vol., no., pp.121-128, 8-10 Dec. 2008</ref>.

The following are the functions for using mutexes:<ref>http://pic.dhe.ibm.com/infocenter/aix/v7r1/index.jsp?topic=%2Fcom.ibm.aix.genprogc%2Fdoc%2Fgenprogc%2Fmutexes.htm</ref>

Initialising the mutex

pthread_mutex_init (pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr): The mutex referenced by the mutex is initialised with the attributes specified by attr using this function. The default mutex attributes are used if attribute passed is NULL.Passing a NULL attribute implies passing the address of a default mutex. The state of the mutex is initialized and unlocked,upon successful initialization.

The pthread_mutex_init can be used to reinitialize an already destroyed mutex,but attempting to initialize an already initialized mutex results in undefined behavior. The macro PTHREAD_MUTEX_INITIALIZER is used to initialize mutexes that are statically allocated in cases where default mutex attributes are appropriate. It is dynamic initialization by a call with parameter attr specified as NULL to pthread_mutex_init() but in this case no error checks are performed.

Return Value: The function returns zero on success; otherwise, an error number is returned to indicate the error.

Destroying the mutex

pthread_mutex_destroy (pthread_mutex_t *mutex): This function is used to destroy a mutex which is no longer needed. The function destroys the mutex object passed by mutex attribute and hence the mutex object becomes uninitialized. pthread_mutex_destroy() sets the object referenced to an invalid value. A destroyed mutex object can be reinitialized using pthread_mutex_init().A mutex cannot be referenced after it is destroyed.It is advised to destroy an initialized mutex that is unlocked. Attempting to destroy a locked mutex results in undefined behavior.

Return Value: The function returns zero on success; otherwise, an error number is returned to indicate the error.

Locking the mutex

pthread_mutex_lock (pthread_mutex_t *mutex): This function is used to lock the mutex passed. If the mutex is already locked by another process, the calling thread blocks until the mutex is unlocked by the other process.This operation returns the mutex object referenced by mutex in the locked state with the calling thread as its owner.Error checking is provided if the mutex is of type PTHREAD_MUTEX_ERRORCHECK. Error shall be returned if a thread attempts to relock a mutex that it has already locked or if a thread attempts to unlock a mutex that it has not locked or a mutex which is unlocked.

Mutexes of type,PTHREAD_MUTEX_RECURSIVE<ref>http://developer.apple.com/library/ios/#documentation/System/Conceptual/ManPages_iPhoneOS/man3/pthread_mutexattr_settype.3.html</ref> maintain a lock count. The lock count is set to one when a mutex is acquired by a thread successfully for the first time. And the lock count is incremented in units of one every time a thread relocks this mutex. Each time the thread unlocks the mutex, the lock count is decremented by one. When the lock count reaches zero, the mutex becomes available for other threads to acquire.An error is returned if a thread attempts to unlock a mutex that it has not locked or a mutex which is unlocked.

If the mutex type is PTHREAD_MUTEX_DEFAULT, attempting to recursively lock the mutex or attempting to unlock the mutex if it was not locked by the calling thread or attempting to unlock the mutex if it is not locked results in undefined behavior.If a signal is delivered to a thread waiting for a mutex, upon return from the signal handler the thread shall resume waiting for the mutex as if it was not interrupted.

Return Value: The functions return a zero on success; otherwise, an error number is returned to indicate the error.

Unlocking the mutex

pthread_mutex_unlock (pthread_mutex_t *mutex): This function is used to release a mutex that is previously locked.The function shall release the mutex object referenced by mutex. The manner in which a mutex is released is dependent upon the mutex's type attribute.If there are threads blocked on the mutex object referenced by mutex when pthread_mutex_unlock() is called, resulting in the mutex becoming available, the scheduling policy shall determine which thread shall acquire the mutex. An error is returned if mutex is already unlocked or owned by another thread.

Return Value: The functions return a zero on success; otherwise, an error number is returned to indicate the error.

Pseudocode
   
    pthread_mutex_t *mutex,
    const pthread_mutexattr_t *attr;
    int p, p1, pu, pd;
    p = pthread_mutex_init(mutex, attr);
    
    if(p!=0)
         printf("Error occurred mutex was not created”);
    
    pl = pthread_mutex_lock(mutex);     
    if(pl!=0)
         printf("Error occurred mutex was not locked”);
    
    /*critical section*/
    pu = pthread_mutex_unlock(mutex);
    if(pu!=0)
         printf("Error occurred mutex was not unlocked”);
    
    pd = pthread_mutex_destroy(mutex);
    if(pd!=0)
         printf("Error occurred mutex was not destroyed”);
    
Avoiding Deadlock<ref>http://www2.chrishardick.com:1099/Notes/Computing/C/pthreads/mutexes.html</ref>

Deadlocks occur when the program holds more than one mutex. A classic example of deadlock is;

Thread 1:

   lock mutex_a
   |
   lock mutex_b
   -blocked forever waiting for mutex_b

Thread 2:

   lock mutex_b
   |
   lock mutex_a
   -blocked forever waiting for mutex a


Few common techniques<ref>http://pages.cs.wisc.edu/~remzi/Classes/537/Fall2011/Book/threads-deadlock.pdf</ref> exist which can be used to avoid deadlocks, which are;

1. Establish a locking hierarchy.<ref>http://software.intel.com/sites/products/documentation/doclib/stdxe/2013/inspectorxe/lin/ug_docs/GUID-38B68BDA-257C-4D4E-9AC9-B0B2698AD950.htm</ref>

2. Spinlock.

3. Chaining.


1. Establish a locking hierarchy:

• A hierarchy needs to be established to hold multiple locks.

• A rule could be established such that in order to lock mutex_a and mutex_b, mutex_a must be locked before mutex_b.

• If unnecessary then both locks should not be held simultaneously.

• Order of locking the mutexes must be maintained.

• Mutexes can be unlocked in any order that is preferred by the program, because unlocking doesn't create deadlocks.

• Another function must be formulated in order to unlock the set of mutexes.


Thread 1:

   lock mutex_a
   lock mutex_b
   
   //perform processing
   
   unlock mutex_a
   unlock mutex_b
   ...

Thread 2:

   lock mutex_a(blocked)
   
   wake up(obtained mutex_a)
   lock mutex_b
   
   //perform processing
   
   unlock mutex_a
   unlock mutex_b
   ...

2. Spin lock:

• The first mutex can be locked without any constraints. But from here on to lock additional mutexes non-blocking mutexes<ref>http://docs.oracle.com/cd/E19683-01/806-6867/sync-36993/index.html</ref> must be used (pthread_mutex_trylock())

• In case of a failure in any lock, unlock in reverse order and try again.

• This method of unlocking in the reverse order reduces the spinning for other threads.


Thread 1:

   lock mutex_a
   try-lock mutex_b
   |
   perform processing 
   | 
   unlock mutex_b
   unlock mutex_a  
   |        
   ...

Thread 2:

   lock mutex_a (blocked)
   
   wake up (obtained mutex_a)
   try-lock mutex_b
   |
   perform processing
   |
   unlock mutex_b
   unlock mutex_a

3. Chaining:

• Traversing linked lists and other data structures.

• A locking hierarchy is to be created, like Lock1, Lock2, Lock3, Unlock1, Lock4.

Thread 1

   lock head node  
   head node processing  
   |                    
   traverse branch locking first node 
   unlock head node 
   first node processing

Conditional Variables

Conditional variables<ref>http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp</ref> are a kind of synchronization objects that are used to allow threads to wait for certain events to occur and are slightly more complex than mutexes. In order to ensure a safe and consistent serialization, usage of condition variables requires the thread to cooperatively use a specific protocol which includes a mutex, a boolean predicate and the condition variable itself. The threads that are cooperating using condition variables can wait for a condition to occur, or can wake up other threads that are waiting for a condition.

The following are the functions used in conjunction with the conditional variable:

Creating/Destroying

int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr): This function is used to initialize the conditional variable referenced by 'cond' with attributes referenced by 'attr'. Default condition variable attributes shall be used if attribute is NULL.It is same as passing the address of a default condition variable attributes object.Upon successful initialization, the conditional variable state is initialized. Attempting to initialize an already initialized condition variable results in undefined behavior.

Return Value: If successful the function returns zero; otherwise, an error number is returned to indicate the error.

pthread_cond_destroy(pthread_cond_t *cond): This function destroys the given condition variable specified by cond; the object becomes, in effect, uninitialized.An implementation may cause pthread_cond_destroy() to set the object referenced by cond to an invalid value.An already destroyed condition variable object can be reinitialized using pthread_cond_init(); the results of otherwise referencing the object after it has been destroyed are undefined. It shall be safe to destroy an initialized condition variable upon which no threads are currently blocked. Attempting to destroy condition variable upon which other threads are currently blocked results in an undefined behavior.

Return Value: If successful the function returns zero; otherwise, an error number is returned to indicate the error.

For example<ref>http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html#BASICS</ref>, consider the following code:

 struct list 
 {
    pthread_mutex_t lm;
    ...
 }
 struct elt 
 {
    key k;
    int busy;
    pthread_cond_t notbusy;
    ...
 }
 /* Find a list element and reserve it. */
 struct elt * list_find(struct list *lp, key k)
 {
    struct elt *ep;
      pthread_mutex_lock(&lp->lm);
      while ((ep = find_elt(l, k) != NULL) && ep->busy)
      pthread_cond_wait(&ep->notbusy, &lp->lm);
      if (ep != NULL)
      ep->busy = 1;
      pthread_mutex_unlock(&lp->lm);
      return(ep);
 }
 delete_elt(struct list *lp, struct elt *ep)
 {
    pthread_mutex_lock(&lp->lm);
    assert(ep->busy);
    ... remove ep from list ...
    ep->busy = 0;	 /* Paranoid. */
      (A) pthread_cond_broadcast(&ep->notbusy);
       pthread_mutex_unlock(&lp->lm);
      (B) pthread_cond_destroy(&rp->notbusy);
       free(ep); 
  }

In this example, the condition variable and its list element may be freed (line B) immediately after all threads waiting for it are awakened (line A), since the mutex and the code ensure that no other thread can touch the element to be deleted.

Waiting on condition

These functions are used to block a condition variable.

int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime); and int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex): These functions are called with mutex locked by the calling thread or undefined behavior results.They atomically release mutex and cause the calling thread to block on the condition variable cond; atomically here means atomically with respect to access by another thread to the mutex and then the condition variable. That is, if another thread is able to acquire the mutex after the about-to-block thread has released it, then a subsequent call to pthread_cond_broadcast() or pthread_cond_signal() in that thread shall behave as if it were issued after the about-to-block thread has blocked.The mutex would be locked and be owned by the calling thread upon successful return.

Waking thread based on condition

These functions unblock threads blocked on a condition variable.

pthread_cond_broadcast(pthread_cond_t *cond): and pthread_cond_signal(pthread_cond_t *cond): The pthread_cond_broadcast() function unblocks all threads currently blocked on the specified condition variable cond. The pthread_cond_signal() function unblocks at least one of the threads that are blocked on the specified condition variable cond (if any threads are blocked on cond).

If more than one thread is blocked on a condition variable, the scheduling policy determines the order in which threads are unblocked.When each thread unblocked as a result of a pthread_cond_broadcast() or pthread_cond_signal() returns from its call to pthread_cond_wait() or pthread_cond_timedwait(), the thread owns the mutex with which it called pthread_cond_wait() or pthread_cond_timedwait().The thread(s) that are unblocked contend for the mutex according to the scheduling policy and as if each had called pthread_mutex_lock().

Barriers

A barrier<ref>http://www.cs.utah.edu/~retrac/papers/jpdc05.pdf</ref> is a type of synchronization method which is used for a group of threads or processes in the source code. It basically stops any thread/process at a certain point till all other threads/processes reach it. Only then are the processes are allowed to proceed.

Initialising the Barrier

int pthread_barrier_init(pthread_barrier_t *restrict barrier, const pthread_barrierattr_t *restrict attr, unsigned count): The init function initializes the barrier with the specified attributes and reserves any resources required to use the barrier. Attempting to initialize an already initialized barrier or initializing a barrier when any thread is blocked on the barrier or using an uninitialized barrier would lead to undefined results.

The count argument specified the number of threads that must call before any of the them successfully return from the call and hence it should be a positive number greater than zero.Failure of the init function results in non initialization of the barrier and the contents of barrier are undefined.Only the object referenced by barrier may be used for performing synchronization. The result of referring to copies of that object in calls to pthread_barrier_destroy() or pthread_barrier_wait() is undefined.

Return Value: Upon successful completion, these functions shall return zero; otherwise, an error number shall be returned to indicate the error.

Barrier Wait

The wait function is used to synchronize parallel threads.

int pthread_barrier_wait(pthread_barrier_t *barrier): Until a required number of threads call pthread_barrier_wait() referring the barrier, the calling thread blocks.When the required number of threads call the barrier referenced, a zero value is returned to all the threads, except for one.The constant PTHREAD_BARRIER_SERIAL_THREAD is returned to one unspecified thread.And then it is sent to the state it has as a result of the most recent init function.

When the required number of threads have arrived at the barrier during the execution of a signal handler, it marks the completion of barrier wait.If a signal is delivered to a thread blocked on a barrier, upon return from the signal handler the thread resumes waiting at the barrier if the barrier wait has not completed; otherwise, the thread continues as normal from the completed barrier wait. Until the thread in the signal handler returns from it, it is unspecified whether other threads may proceed past the barrier once they have all reached it.A thread that has blocked on a barrier does not prevent any unblocked thread that is eligible to use the same processing resources from eventually making forward progress in its execution. Eligibility for processing resources is determined by the scheduling policy.

Return Value: Upon successful completion, the function shall return PTHREAD_BARRIER_SERIAL_THREAD for an arbitrary thread synchronized at the barrier and zero for each of the other threads. Otherwise, an error number shall be returned to indicate the error.

Destroying the Barrier

int pthread_barrier_destroy(pthread_barrier_t *barrier):This function is used to destroy the barrier passed by the barrier attribute and also releases any resources used by the barrier. A destroyed barrier can be reused when reinitialized by another call to pthread_barrier_init().The destroyed barrier is set to an invalid value. The results are undefined if pthread_barrier_destroy() is called when any thread is blocked on the barrier, or if this function is called with an uninitialized barrier.

Return Value: Upon successful completion, the functions returns zero; otherwise, an error number is returned to indicate the error.

Pseudocode
   
   pthread_barrier_t *barrier;
   pthread_barrierattr_t *attr;
   unsigned int count;
   int i = pthread_barrier_init(barrier, attr, count);             // initialize the barrier
   
   if(i!=0)
      printf(“Error occurred barrier was not initialized”):
   
   int b = pthread_barrier_wait(barrier);                          //synchronize participating threads
   if(b!=0)
      printf(“Error occurred in synchronizing threads”);
   
   /* critical section */
   
   int d = pthread_barrier_destroy(barrier);                       //destroy the barrier
   if(d!=0)
      printf(“Error occurred barrier was not destroyed”):
   

Synchronization Mechanisms Examples

DOALL parallelism is supported by parallelization mechanisms like semaphore, mutex, condition variable and barrier depending on applications. DOACROSS and DOPIPE parallelism are supported by point to point synchronization mechanisms like semaphore and mutex.

DOALL Parallelism


Consider the following code, amenable to DOALL parallelism.

Code Segment

    for ( i = 1 ; i <= N ; i++ )
    {
       S1: a[i] = b[i] + c[i];      /* can be parallelized */
       S2: sum  = sum + a[i] ;      /* critical section that must be protected by synchronization mechanism */
    }

There are no loop dependencies for S1 and S2, but we can see that "sum" is a critical variable. "sum" can be protected using various synchronization mechanisms like semaphores, mutexes and condition variables. They are illustrated as follows.

Semaphore Pseudocode

   sem_t * sem;
   sem_init ( sem , 0 , 1 );        /*initialize the semaphore variable*/
   for ( i =1 ; i <= N ; i++ )      /*parallelize the for loop*/
   {       
           a[i] = b[i] + c[i];
           sem_wait(sem);           /*enter critical section if sem ==0*/
           sum  = sum + a[i] ;
           sem_post(sem);           /*exit critical section*/
   }

Even though semaphore achieves the objective of protecting the critical section, mutex provides additional security by preventing accidental deletion of locks. This property is due to the exclusive ownership property associated with mutex variables where only the locked mutex can unlock the critical section.

Mutex Pseudocode

   pthread_mutext * mut_id;
   pthread_mutex_init (mut_id);             /*initialize mutex variable */
   for ( i =1 ; i <= N ; i++ )              /* parallelize the for loop */
   {    
           a[i] = b[i] + c[i];
           pthread_mutex_lock ( mut_id );   /* enter critical section if mut_id is free*/
           sum = sum + a[i];
           pthread_mutex_unlock ( mut_id ); /*exit critical section*/
   }

Suppose in the above example the thread has to wait for some other arbitrary process to complete in the critical section, then conditional variable synchronization can be used. Here the mutex will wait until a condition variable is satisfied. The setting of a condition variable is controlled by other another thread. This is illustrated as follows.

Conditional Variable Pseudocode

   //thread 1: main thread
   pthread_condition_t * cond;
   pthread_mutex_init ( mut_id );
   for ( i =1 ; i <= N ; i++ ) // parallelize the for loop
   {
       a[i] = b[i] + c[i];
       pthread_mutex_lock ( mut_id );   /*enter critical section if mut_id is free*/
       sum = sum + a[i];
       pthread_cond_wait(cond,mut_id);  /*this thread goes to sleep until ‘cond’ condition is satisfied*/
       pthread_mutex_unlock ( mut_id ); /*exit critical section*/
   }
   //thread 2: condition signaling 
   while (i > 0)
   i -- ;
   if (i == 0)
   {	pthread_mutex_lock (mut_id);       /* mut_id indicates thread 1 mutex is targeted by this condition */
       pthread_cond_signal (cond,mut_id); /* set condition variable*/
       pthread_mutex_unlock ( mut_id );   /* exit mutex*/
   }

The previous example does not mandate barrier synchronization, as the purpose was to avoid shared memory read contention. The purpose of barrier synchronization is to address the case when one needs to complete all parallel tasks until a common point before proceeding. Consider the following code, amenable to DOALL parallelism, slightly modified for illustrating barrier synchronization.

   for ( i = 1 ; i <= N ; i++ )
   {	
       a[i] = b[i] + c[i] ;
       min(a);	              /*computes the minimum value from array a*/
   }

In the above example, minimum of "a" can be calculated only after the computations for "a" is complete. The Barrier implementation for the above code segment is shown below:

Barrier Pseudocode

   pthread_barrier_t* bar;
   pthread_barrier_init (bar, attr, nthreads); /*initialize barrier variable*/
   for ( i=1 ; i <= N ; i++ )                  /* parallelize the for loop*/
   {   
       a[i] = b[i] + c[i];
       pthread_barrier_wait (bar);             /* Post the barrier*/
	min(a);                                 /*computes the minimum value from array a */
   }

DOACROSS Parallelism


Consider the following code, amenable to DOACROSS parallelism

   for ( i = 1 ; i <= N ; i++ )
   {
       S1: d[i] = b[i] * c[i] ;  /*no loop dependencies*/
       S2: a[i] = a[i-1] + d[i]; /* loop dependency present*/
   }

S1 does not have any inter loop dependencies. However, S2 is dependent on S1, and S2 has inter loop dependencies. Thus we can parallelize S1 without any synchronization. However, we need synchronization mechanisms for S2. The above code can be parallelized using semaphores and mutexes. The advantages of using mutex over semaphore is the same as mentioned before in DOALL parallelism. They are illustrated as follows.

Semaphore Pseudocode

   sem_t * sem;                    /* a vector of semaphores used to keep track of each loop */
   for ( i =1 ; i <= N ; i++ )
   {
       sem_init( sem[i], 0 ,1);  /* one semaphore initialized for each iteration */
       S1: d[i] = b[i] * c[i];   /* no dependencies, hence parallel execution */
       sem_wait( sem[i-1]);
       S2: a[i] = a[i-1] + d[i]; /*executes only if S2 in previous loop completes execution*/
       sem_post(sem[i]);
   }

Mutex Pseudocode

   pthread_mutext * mut_id;// a vector of semaphores of length N is  used 
   for ( i =1 ; i <= N ; i++ )
   {
       pthread_mutex_init (mut_id[i]);      /*one mutex initialized for each iteration*/
       S1: d[i] = b[i] * c[i];
       pthread_mutex_lock ( mut_id [i-1] ); /* no dependencies, hence parallel execution*/
       S2: a[i] = a[i-1] +d[i];             /*executes only if S2 in previous loop completes execution*/
       pthread_mutex_unlock ( mut_id [i]);
   }

DOPIPE Parallelism


Consider the following code, amenable to DOPIPE parallelism

   for ( i = 1 ; i <= N ; i++ )
   {
       S1: a[i] = a[i-1] + b[i] ; /* loop dependent statement */
       S2: c[i] = c[i] + a[i];    /* loop independent but dependent on S1 */
   }

S1 has inter loop dependencies. S2 depends on S1 even though S2 does not have loop dependencies. Hence S2 can be executed only after S1 is executed in each loop. This necessitates the use of synchronization mechanisms. The above code can be parallelized using semaphores and mutexes. They are illustrated as follows.

Semaphore Pseudodode

   sem_t * sem;
   for ( i = 1 ; i <= N ; i++ )
   {
       sem_init(sem[i] , 0 ,1);    /*initialize all N semaphore variables*/
   }
   for ( i = 1 ; i <= N ; i++ )
   {
       S1: a[i] = a[i-1] + b[i] ; /*loop dependent statement executed first*/
       sem_post (sem[i]);         /*Tell second loop that S1 is completed*/
   }
   for ( i = 1 ; i <= N ; i++ )
   { 
       sem_wait(sem[i]);          /*Wait for S1 to complete in first loop*/
       S2: c[i] = c[i] + a[i] ;   /*Execute once synchronization is done*/
   }

Mutex Pseudocode

   pthread_mutex_t * mut_id;
   for ( i = 1 ; i <= N ; i++ )
   {
       pthread_mutex_init(mut_id[i]); /*initialize all mutex variables*/
   }
   for ( i = 1 ; i <= N ; i++ )
   {
       S1: a[i] = a[i-1] + b[i] ;        /*loop dependent statement executed first*/
       pthread_mutex_unlock (mut_id[i]); /*Tell second loop that S1 is completed*/
   }
   for ( i = 1 ; i <= N ; i++ )
   {
       pthread_mutex_lock (mut_id[i]);   /*Wait for S1 to complete in first loop */
       S2: c[i] = c[i] + a[i];           /*Execute once synchronization is done */
   }

References

<References>http://linux.die.net/man/3/

http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp
http://maxim.int.ru/bookshelf/PthreadsProgram/toc.html
http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html#BASICS

</References>