← Design Verification Interviews
Interview Question · Code Reading
Forking Workers Inside a Loop
The Question
The interviewer asks
What does this print, and how do you make each worker see its own index?
initial begin
for (int i = 0; i < 3; i++)
fork
$display("worker %0d", i);
join_none
wait fork;
endYou have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
It prints worker 3 three times. With join_none, the forked processes start only when the parent blocks at wait fork. By then the loop has finished, and the one loop variable i holds 3. Give each pass its own copy: declare automatic int k = i; inside the fork, before the statement, and print k.
- Cycle 0
Iteration 0 forks the first child. With
join_nonethe parent does not wait, and the child does not start yet. - Cycle 3
Iteration 3 forks the fourth child. Four children exist, and none of them has run.
- Cycle 4
ch++makesch4, the loop test fails, and the loop ends. - Cycle 5
The parent blocks, so the children start. Each one reads
chonly now, finds 4, and drives channel 4.
The same race with four children and a loop variable ch. Each column is one step of the parent, all at time 0. The children start only after the loop ends, so all of them read 4.
All workers share i
fork
$display("worker %0d", i);
join_none
Runs after the loop: prints 3, 3, 3
Each worker owns k
fork
automatic int k = i;
$display("worker %0d", k);
join_none
k is set as each fork is created: 0, 1, 2
Self-Check
Tick each key point you covered in your answer.
What Interviewers Listen For (Fresher)
A good fresher answer predicts three 3s. It explains that join_none children start only when the parent process blocks.
What Interviewers Listen For (Junior)
A good junior answer writes the automatic copy inside the fork. It explains that the copy is set when the fork runs, while the statements run later.
What Interviewers Listen For (Senior)
A good senior answer mentions that simulators disagree on this exact code. It makes the automatic copy a coding rule, so the bench does not depend on one simulator.
Cross-Questions
Where the interviewer goes next. Open a node to practise that follow-up.
WhyWhat IfProve ItCompare
- Forking Workers Inside a Loop
-
WhyWhy the Automatic Copy Gets the Right ValueL1 Junior
The statements inside the fork run after the loop. Why does
automatic int k = i;still get 0, 1 and 2?2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
Declarations at the top of a fork block are initialised when the fork statement runs, in the parent. This happens before any child process starts. So each pass creates a new
kholding that pass'si, and the child that later runs refers to its ownk.Where Each Child Gets Its Channel NumberTwo loops that fork four children: one shares the loop variable ch, one gives each child its ownk. Arrows show data: values written into a variable, or read from it by the children.Read the diagram as text
- Parent loop: for (ch = 0; ch < 4; ch++)
- ch: static: one variable
- Four children: drive_channel(...)
- k, one per child: automatic int k = ch
- hits[0:4]: drives per channel
- Parent loop → ch: ch++
- ch → Four children: read when a child runs
- Parent loop → k, one per child: filled at the fork
- k, one per child → Four children: each reads its own
- Four children → hits[0:4]: hits[c]++
A value copied in the parent, at the fork, is safe from the loop that keeps running.
Self-Check
Tick each key point you covered in your answer.
Buzzword Without Mechanism
"
automaticmakes the variable thread-safe."It gives each activation its own storage. Two processes that share one automatic variable can still race on it.
-
WhyWhy Every Child Sees the Final IndexL1 Junior
Without the copy, every child prints 3, not 2. Why the value that ended the loop?
2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
The loop stops when
ibecomes 3 and the test fails. The children ofjoin_nonestart only when the parent blocks, which is after the loop has finished. At that pointiholds 3, the value that ended the loop. So every child prints 3.Self-Check
Tick each key point you covered in your answer.
Misconception
"Each child sees the value of
ifrom the pass that forked it."A child reads the shared loop variable when it runs, not when it is forked. By then the loop has ended.
Source IEEE 1800-2017 §9.3.2
-
CompareStatic vs Automatic Tasks Called in ParallelL1 JuniorL2 Mid-Level
Compare a static and an automatic task when two threads call each at the same time. What does this print?
systemverilog module tb; // A task declared without 'automatic' in a module is static. task wait_and_report(int id, int delay); #delay $display("t=%0t static task reports id %0d", $time, id); endtask task automatic wait_and_report_auto(int id, int delay); #delay $display("t=%0t automatic task reports id %0d", $time, id); endtask initial fork wait_and_report(1, 10); wait_and_report(2, 20); wait_and_report_auto(1, 30); wait_and_report_auto(2, 40); join endmodule2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
Both static calls report id 2. A static task has one set of arguments shared by every call, and the second call overwrote the first while it waited. The automatic calls report 1 and 2, because each call gets its own arguments. Tasks in modules are static unless declared
automatic; class methods are always automatic.One Shared Id, or One Id per CallTwo overlapping calls of a task report(id, delay), first as a static task, then as an automatic one. Arrows show data: a call writes its argument intoidwhen it starts, and readsidback when it prints.Illustrative sequenceCallValueReturnWaiting- Call A startst=2 (illustrative)
The static
report(1, 5)stores 1 in the oneidand sleeps for 5 time units.Follow the calls, values and waits
- data 1: Call A → id (static task)
- Waiting: Call A — sleeps until t=7
- Call B startst=3 (illustrative)
report(2, 1)stores 2 in the sameid. The 1 that call A stored is gone.Follow the calls, values and waits
- data 2: Call B → id (static task)
- Waiting: Call B — sleeps until t=4
- Call B printst=4 (illustrative)
Call B reads
idand printsid=2, which happens to be right.Follow the calls, values and waits
- data 2: id (static task) → Call B
- Released: Call B
- Call A wakest=7 (illustrative)
Call A reads the same
idand printsid=2as well.Follow the calls, values and waits
- data 2: id (static task) → Call A
- Released: Call A
- Automatic: a fresh id per callt=7, t=8 (illustrative)
report_ais declaredautomatic, so each call creates its ownid. Call B writes 2 into its own variable and cannot touch call A's 1.Follow the calls, values and waits
- data 1: Call A → id of call A
- data 2: Call B → id of call B
- Waiting: Call A — sleeps until t=12
- Waiting: Call B — sleeps until t=9
- Each call prints its own valuet=9, t=12 (illustrative)
Call B prints
id=2at t=9. Call A wakes at t=12, reads its ownid, and printsid=1.Follow the calls, values and waits
- data 2: id of call B → Call B
- data 1: id of call A → Call A
- Released: Call A
- Released: Call B
Read the diagram as text
- Call A: report(1, 5)
- Call B: report(2, 1)
- id (static task): one variable for all calls
- id of call A: automatic task
- id of call B: automatic task
- Call A → id (static task): static
- Call B → id (static task): static
- Call A → id of call A: automatic
- Call B → id of call B: automatic
Same calls, same times. Only the lifetime of
iddiffers.RUNVerilator · simulator serviceExpected:t=10 static task reports id 2t=20 static task reports id 2t=30 automatic task reports id 1t=40 automatic task reports id 2Self-Check
Tick each key point you covered in your answer.
Misconception
"Each call to a task gets its own copy of the arguments."
Only automatic tasks do. A static task's arguments live in one place, so concurrent calls overwrite each other, as the run shows.
Source IEEE 1800-2017 §13.3.2
- Call A startst=2 (illustrative)
-
Prove ItSolve 3.2.1: Invocation-Local AccumulatorSimulator-graded
Show it, don't just say it: this Silicon Lab problem is graded by the simulator.
-
Prove ItSolve 3.2.1: Invocation-Local AccumulatorSimulator-graded
Show it, don't just say it: this Silicon Lab problem is graded by the simulator.
-
What IfWhat Wait Fork Waits ForL1 JuniorL2 Mid-Level
Asked if they drop the
wait forkWhat if the
wait forkis removed, or the loop is moved into a task that the test calls? What doeswait forkactually wait for?2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
Without it, the
initialblock ends while the workers still run. Nothing waits for them, so a test can finish in the middle of their work.wait forkwaits for every child process of the calling process. That includes children forked earlier for other reasons, such as a background monitor that never ends. Wrap the workers in their ownfork begin ... end joinwhen you only mean them.Self-Check
Tick each key point you covered in your answer.
Misconception
"
wait forkwaits for the fork statement just above it."It waits for all immediate children of the current process, whichever fork created them.
Source IEEE 1800-2017 §9.6.1
What People Get Wrong
Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.
Misconception
"Each worker keeps the value of i from the pass that forked it."
The forked statement reads i when it runs, not when it was forked, and they all run after the loop. The twin prints three 3s.
Run It
The interview code, with a check on what the first worker saw.
worker 3 worker 3 worker 3 sum of the indexes the workers saw: 9 FAIL: the workers start after the loop ends and all read the one shared i, now 3Tool as Truth
"It prints 0, 1, 2 on Verilator, so the code is fine."
Verilator 5.052 prints 0, 1, 2 for this code, while the standard's own example in §9.3.2 needs the automatic copy to get distinct values. Icarus 12 prints 3, 3, 3.
Source IEEE 1800-2017 §9.3.2; measured: Verilator 5.052 prints worker 0, 1, 2, Icarus 12 prints worker 3 three times
Half-Truth
"Use join instead of join_none to fix it."
That does print 0, 1, 2, but the workers then run one after another, which defeats the point of forking them in parallel.