Self-Assessment Quiz: OpenMP
Twenty questions to confirm you can scope a parallel region correctly and spot a race before it costs you a run. Aim for 16 or more. Answers and a topic map are at the end — try the whole quiz first.
Question 1
In the fork–join model, at !$omp end parallel the program:
- A. Terminates
- B. Joins the team back to the single master thread and continues serially
- C. Forks a second team
- D. Waits for the user to press a key
Question 2
Which flag enables OpenMP in gfortran?
- A. -O3
- B. -fcoarray=single
- C. -fopenmp
- D. -parallel
Question 3
Compiled without the OpenMP flag, a source file full of !$omp directives:
- A. Fails to compile
- B. Compiles and runs as a correct serial program (the directives are comments)
- C. Runs in parallel anyway
- D. Deletes the directives from the file
Question 4
omp_get_thread_num() returns, for the master thread:
- A. 1
- B. The total number of threads
- C. 0
- D. A random integer
Question 5
The !$omp do construct distributes a loop's iterations so that each iteration runs:
- A. Once per thread (so the loop body executes team-size times as often)
- B. Exactly once, on one thread of the team
- C. Only on the master thread
- D. Twice, for error checking
Question 6
True or false, with one sentence of justification: "A !$omp do directive placed outside any parallel region
still runs the loop in parallel."
Question 7
The default data-sharing attribute that OpenMP assigns to a variable you forget to scope is:
- A. private
- B. firstprivate
- C. shared
- D. reduction
Question 8
The purpose of the default(none) clause is to:
- A. Disable all parallelism
- B. Force you to give every variable in the region an explicit data-sharing attribute
- C. Make every variable private
- D. Turn off scheduling
Question 9
Summing an array with a shared accumulator and no reduction (s = s + x(i)) across a team produces:
- A. The correct sum, always
- B. A compiler error
- C. A wrong sum that varies from run to run (a data race)
- D. A sum that is always exactly zero
Question 10
Each thread's private copy of the accumulator in reduction(+:s) is initialized to:
- A. The value s had before the region
- B. 1
- C. 0 (the identity for +)
- D. huge(s)
Question 11
The difference between private(x) and firstprivate(x) is that firstprivate:
- A. Makes x shared
- B. Initializes each thread's copy to x's pre-region value
- C. Copies the last iteration's value back out
- D. Is only legal for arrays
Question 12
Which loop iteration variable is made private automatically, without you listing it?
- A. Every variable in the loop body
- B. The iteration variable of the loop associated with !$omp do (the outer index)
- C. All inner loop indices
- D. None; you must list every index
Question 13
For combining per-thread partial results, the fastest-to-slowest ranking of mechanisms is:
- A. critical > atomic > reduction
- B. reduction > atomic > critical
- C. atomic > reduction > critical
- D. They are all equally fast
Question 14
schedule(static) is the right choice when:
- A. Iterations vary wildly in cost
- B. Every iteration costs about the same (uniform work) and you want reproducible, low-overhead assignment
- C. You need dynamic load balancing
- D. The loop has an unknown trip count
Question 15
schedule(dynamic) earns its extra overhead when:
- A. The work per iteration is uniform
- B. The work per iteration is uneven, so idle threads can grab more chunks
- C. You have only one thread
- D. You want deterministic iteration assignment
Question 16
False sharing is: - A. Two threads correctly sharing read-only data - B. Different threads writing different variables that land on the same cache line, causing coherence traffic - C. A compiler error about shared clauses - D. A synonym for a data race
Question 17
True or false, with justification: "The OpenMP heat solver can give a slightly different temperature field than the serial solver, because the threads run in a nondeterministic order."
Question 18
!$omp simd provides parallelism by:
- A. Splitting iterations across threads
- B. Vectorizing a loop so one core processes several elements per instruction
- C. Launching a GPU kernel
- D. Creating a new team
Question 19
You would reach for !$omp task` instead of `!$omp do when:
- A. The loop has a known, countable trip count
- B. The work is irregular or recursive (tree/list traversal) and cannot be written as a counted loop
- C. You want the fastest possible array sweep
- D. You need a reduction
Question 20
What does this print, and what part is nondeterministic?
!$omp parallel do default(none) private(i) reduction(+:s)
do i = 1, 4
s = s + real(i, dp) ! s initialized to 0.0_dp before the region
end do
!$omp end parallel do
print '(f6.1)', s
- A.
10.0, and nothing is nondeterministic about the printed value - B. A different number each run
- C.
0.0always - D. It fails to compile
Answer Key
| Q | Ans | Why |
|---|---|---|
| 1 | B | end parallel joins the team; the master continues alone, serially. |
| 2 | C | -fopenmp enables the directives and links the runtime. |
| 3 | B | !$omp lines are comments without the flag — the same source is correct serial code. |
| 4 | C | The master is always thread 0. |
| 5 | B | Work sharing partitions iterations: each runs once, on one thread. |
| 6 | False | With no team to share among, !$omp do just runs serially on the master — no parallelism. |
| 7 | C | The dangerous default is shared, which races on anything you write. |
| 8 | B | default(none) forces an explicit attribute for every variable. |
| 9 | C | Unsynchronized read–add–write of a shared scalar is a data race: wrong and run-to-run-varying. |
| 10 | C | Each private copy starts at the operator's identity — 0 for +. |
| 11 | B | firstprivate initializes each copy to the pre-region value; plain private is uninitialized. |
| 12 | B | Only the !$omp do loop's own (outer) index is auto-private; inner indices are your job. |
| 13 | B | reduction (no contention) > atomic (one cheap update) > critical (a general lock). |
| 14 | B | static is cheapest and reproducible for uniform work. |
| 15 | B | dynamic self-balances uneven work, repaying its hand-out overhead. |
| 16 | B | False sharing = different variables on one cache line → coherence ping-pong; correct but slow. |
| 17 | False | The result is deterministic and must match the serial solver; only the schedule is nondeterministic. |
| 18 | B | simd vectorizes within a thread (multiple data per instruction). |
| 19 | B | task is for irregular/recursive work a counted loop can't express. |
| 20 | A | 1+2+3+4 = 10.0; the reduction makes the result deterministic. Only the schedule (invisible here) varies. |
Topics to review by question
- Q1–4 → §33.1 (fork–join, the flag, thread ids).
- Q5–6, 14–15 → §33.2 and §33.4 (work sharing and scheduling).
- Q7–12, 20 → §33.3 (data scoping,
default(none),reduction,firstprivate). - Q9, 13, 16–17 → §33.3–33.5 (races, the synchronization ranking, false sharing, determinism).
- Q18–19 → §33.5 (SIMD and tasks).
Scored below 16? Reread §33.3 first — data scoping is where most of these questions, and most real OpenMP bugs, live.