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