1 
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 #include <omp.h>
  5 
  6 int main(int argc, char * argv[]) {
  7 
  8   int x;        // the variable to increment
  9   int count;    // the number of times each variable will increment x
 10   int nThreads; // the number of threads to use
 11   int i;        // a loop counter
 12   omp_lock_t lock; // a traditional lock
 13 
 14   // the argument stream should look like this:
 15   // increment <count> <nThreads>
 16   if(argc!=3) {
 17     fprintf(stderr,"Usage:\n%s <count> <nThreads>\n",argv[0]);
 18     exit(1);
 19   }
 20 
 21   count = atoi(argv[1]);
 22   nThreads = atoi(argv[2]);
 23 
 24   if(count<=0 || nThreads <=0) {
 25     fprintf(stderr,"Count and nThreads must be >0\n");
 26     exit(1);
 27   }
 28 
 29   // arguments parsed successfully
 30   // now start incrementing
 31   omp_set_num_threads(nThreads);
 32   x = 0;
 33 
 34   // must call this if you use locks...
 35   omp_init_lock(&lock);
 36 
 37   // fork a team of threads
 38   #pragma omp parallel \
 39      private(i) \
 40      shared(x,count) 
 41   {
 42 
 43     for(i=0;i<count;i++) {
 44       // use critical section construct to increment
 45       #pragma omp critical
 46       {
 47         // each thread will execute here, but one-at-a-time
 48         x++;
 49 
 50       } // end of critical section
 51     }
 52 
 53     // wait for all threads to finish incrementing
 54     #pragma omp barrier
 55 
 56     #pragma omp master 
 57     {
 58       // only the master thread will execute here (thread id = 0)
 59       fprintf(stdout,"Master thread (id=%i) reports x=%i\n",
 60                       omp_get_thread_num(),
 61                       x);
 62       x = 0;
 63     }
 64 
 65     // wait for the master to print and then reset x
 66     #pragma omp barrier
 67 
 68     // now update x using ATOMIC directive
 69     for(i=0;i<count;i++) {
 70       #pragma omp atomic
 71       x++;
 72     }
 73 
 74     // ensure all threads have done the update
 75     #pragma omp barrier
 76 
 77     #pragma omp single
 78     {
 79        // use of Single means ANY thread may enter, but only one
 80        fprintf(stdout,"            Thread %i reports x=%i\n",
 81                        omp_get_thread_num(),
 82                        x);
 83        x = 0;
 84 
 85     }
 86 
 87     // ensure all threads wait for printing and reset before continue
 88     #pragma omp barrier
 89 
 90     // each thread will now loop, acquiring and releasing the
 91     // omp lock
 92     for(i=0;i<count;i++) {
 93       omp_set_lock(&lock);
 94       // this thread now has the lock
 95       x++;
 96 
 97       // memory must remain consistent -- why?
 98       // Answer: ATOMIC and CRITICAL have built-in flush!
 99       // #pragma omp flush
100 
101       omp_unset_lock(&lock);       // don't forget to unlock
102     }
103 
104     #pragma omp barrier
105 
106     #pragma omp single
107     {
108 
109 
110        // done with the lock
111        omp_destroy_lock(&lock);
112        fprintf(stdout,"            Thread %i reports x=%i\n",
113                        omp_get_thread_num(),
114                        x);
115 
116     }
117   } // JOIN occurs here, with an implicit barrier
118     // end of Parallel
119 
120   exit(0);
121 }
122