Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Puzzle Bank
  • SystemVerilog Language Puzzles25
  • Difficulty Guide
  • Full Topic Map
  • Interview-Day Tips
  • Study Route: One Week Before the Interview
  • Study Route: Two Weeks
  • Study Route: Four Weeks (Full Course)4
  • OOP & Testbench Puzzles25
  • Concurrency & Timing Puzzles25
    • Event Scheduling Puzzles
    • Race Condition Puzzles
      • Competing Active Writers on x
      • Blocking Writer vs NBA Writer Same Signal
      • Reading q Before the NBA (Not a Race)
      • Fork join_none Loop Variable Capture and kill()
      • Lost Update in Forked Counter
      • Two always_ff Writers, One Register
    • Clocking Block Puzzles
    • Semaphore & Mailbox Puzzles
    • Concurrency & Timing Puzzles: Tricky Q&A
  • Randomization & Constraint Puzzles25
  • SVA Assertion Puzzles25
  • Functional Coverage Puzzles25
  • Logic & Aptitude Puzzles25
  • Scenario & Debug Puzzles25
  • UVM Testbench Puzzles25
  • Clock, Reset & CDC Puzzles25
  • Bus and Interface Protocol Puzzles25
  • Interview Prep: Puzzle Rounds7
  • DV Puzzle Cheatsheet
Loading lesson

←Race Condition Puzzles
  1. Topics
  2. DV Interview Puzzles
  3. Concurrency & Timing Puzzles
  4. Race Condition Puzzles
  5. Fork join_none Loop Variable Capture and kill()
On this page

    VLSI DV Interview PuzzlesAll levels

    Fork join_none Loop Variable Capture and kill()

    Predict every line printed. What value does each child of loop A see, which children of loop B finish, and which line order is defined?

    Puzzle

    Difficulty: Medium · Puzzle 4 of 6 · Topic: Race Condition Puzzles

    Predict every line printed. What value does each child of loop A see, which children of loop B finish, and which line order is defined?

    Code

    tb.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    `timescale 1ns/1ns
    module tb;
      int i;                       // static, shared
      process p[3];
    
      initial begin
        for (i = 0; i < 3; i++) begin
          fork
            $display("[%0t] A sees i=%0d", $time, i);
          join_none
        end
    
        for (int j = 0; j < 3; j++) begin
          automatic int k = j;     // per-iteration copy
          fork
            begin
              p[k] = process::self();
              #5;
              $display("[%0t] B finished k=%0d", $time, k);
            end
          join_none
        end
    
        #1;
        p[1].kill();
        #10;
        $finish;
      end
    endmodule

    Hint

    join_none children do not start until the parent blocks; they then read variables as they are at that moment.

    Step-by-step solution

    Diagram
    1) The parent never blocks while looping, so no child of loop A runs until it reaches #1. By then the shared static i is 3, so all three children print i=3 at t=0.
    2) In loop B each iteration has its own automatic k, copied from j at spawn time. The three children see k=0, 1, 2 respectively and each stores its handle in p[k] at t=0.
    3) The parent wakes at t=1 and kills p[1], which is still inside #5.
    4) At t=5 only the surviving children (k=0 and k=2) print B finished. The killed child never prints.
    5) The three A lines are identical, so their order is irrelevant; the order of the two B lines at t=5 is not defined by the LRM.

    Answer

    Answer: Three lines [0] A sees i=3, then at t=5 [5] B finished k=0 and [5] B finished k=2 (either order). k=1 never finishes because p[1].kill() ran at t=1.

    How this was checked

    Checked by running the code in Verilator 5; the printed output supports the answer above. Every loop-A child sees the final i=3, and the killed k=1 child never finishes. The order of the two surviving B lines is undefined, so each is checked in its own run.

    Why candidates get it wrong

    Reading the loop index inside a fork join_none body is the bug: the body sees the final value. Copy it into an automatic variable declared inside the loop body before the fork.

    Interviewer follow-up

    What happens if you call p[1].kill() before p[1] has been assigned, e.g. at t=0 right after the loop? Model answer: p[1] is still null, so the call dereferences a null handle (runtime error). Wait until the handle is set (wait (p[1] != null)) or have the child register itself first.

    Say it out loud

    Loop A prints i equal to 3 three times at time zero, because the parent does not block until the delay and the static loop variable has already reached 3. Loop B copies the index into an automatic variable, so the children see 0, 1 and 2, and the parent kills the one with index 1 at time one. At five, only k equal to 0 and k equal to 2 print, in an order the LRM does not define. The trap is reading the loop variable inside the fork body; I would declare an automatic copy inside the loop before the fork.

    Related topics

    • Threads and Control: Fork, Disable, Wait, Process

    • Back to Race Condition Puzzles

    • Concurrency & Timing Puzzles section

    Previous

    70 / 293

    Next: Lost Update in Forked Counter

    Up next

    Up nextLost Update in Forked Counter

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Competing Active Writers on x
    • Blocking Writer vs NBA Writer Same Signal
    • Two always_ff Writers, One Register