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
    • Clocking Block Puzzles
      • Why Every Sample Is One Cycle Old
      • Interpreting |=> ##1 in Clocking Domain
      • disable fork Kills Unrelated Background Threads
      • input #0 vs input #1step Snapshot
      • Nonzero Input Skew Looks Back in Time
      • Mixing Direct Drive and cb Drive
    • 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

←Clocking Block Puzzles
  1. Topics
  2. DV Interview Puzzles
  3. Concurrency & Timing Puzzles
  4. Clocking Block Puzzles
  5. disable fork Kills Unrelated Background Threads
On this page

    VLSI DV Interview PuzzlesAll levels

    disable fork Kills Unrelated Background Threads

    Predict every line printed and its time. Does the background thread survive the disable fork? What would change if the inner fork were not wrapped in fork begin ... end join?

    Puzzle

    Difficulty: Medium · Puzzle 3 of 6 · Topic: Clocking Block Puzzles

    Predict every line printed and its time. Does the background thread survive the disable fork? What would change if the inner fork were not wrapped in fork begin ... end join?

    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
    `timescale 1ns/1ns
    module tb;
      initial begin
        fork
          begin #30; $display("[%0t] background done", $time); end
        join_none
    
        fork
          begin                        // isolating wrapper
            fork
              begin #10; $display("[%0t] fast done", $time); end
              begin #20; $display("[%0t] slow done", $time); end
            join_any
            disable fork;
          end
        join
    
        $display("[%0t] after join_any", $time);
        #40 $display("[%0t] end", $time);
        $finish;
      end
    endmodule

    Hint

    disable fork kills every active child (and descendant) of the process that executes it, not just the children of the last fork.

    Step-by-step solution

    Diagram
    1) The first fork/join_none starts a background thread (t=30) as a child of the initial process and does not wait for it.
    2) The wrapper fork begin ... end join runs one child process. The inner fork is created inside that child, so fast and slow are descendants of the wrapper child only.
    3) join_any returns at t=10, right after fast prints. disable fork then executes inside the wrapper child and kills only its own descendants: slow (due at t=20) is killed and never prints.
    4) The wrapper child ends, the outer join returns, and [10] after join_any prints. The background thread is a child of the initial process, not of the wrapper, so it is untouched and prints [30] background done.
    5) Output: [10] fast done, [10] after join_any, [30] background done, [50] end. The first two lines have a defined order (fast prints before its process ends).
    6) Without the wrapper, disable fork would run in the initial process itself, whose descendants include the background thread, so [30] background done would be silently lost. Verified in Verilator 5.048: wrapper keeps it, no wrapper loses it (output is [10] fast done, [10] after join_any, [50] end).
    7) Tool note: Icarus kills the background thread in both versions (it does not honour the wrapper isolation), so use Verilator or the LRM (9.6.3) as the reference.

    Answer

    Answer: [10] fast done, [10] after join_any, [30] background done, [50] end. slow never prints (killed at t=10). The background thread survives only because the join_any/disable fork pair is isolated in a fork begin ... end join wrapper; without it disable fork would also kill the background thread and [30] background done would disappear.

    How this was checked

    Checked by running the code in Verilator 5; the printed output supports the answer above. The wrapper keeps disable fork from killing the background thread; slow is killed. Without the wrapper, disable fork also kills the background thread.

    Why candidates get it wrong

    disable fork is not scoped to the fork statement right before it: it disables all active descendants of the calling process. Putting it in a bare initial or task body can kill threads started long before (a monitor, a watchdog, a driver loop). Always isolate the join_any plus disable fork pair.

    Interviewer follow-up

    A task uses join_any plus disable fork and is called from a UVM run_phase that also has forked background monitors. What do you do? Model answer: wrap the join_any/disable fork pair in fork begin ... end join (or call it from a helper task spawned inside such a wrapper) so only the wrapper's own children are killed; alternatively keep handles of the specific processes with process::self() and kill those individually.

    Say it out loud

    The background thread survives, and slow is killed. Disable fork kills all active descendants of the process that calls it, and the wrapper makes the calling process a child that owns only fast and slow. So the output is fast done and after join_any at ten, then background done at thirty, then end at fifty. The trap is thinking disable fork is limited to the fork just before it; without the wrapper it would kill the background thread too. Icarus does not honour that isolation, so I would use the LRM or Verilator as the reference.

    Related topics

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

    • Back to Clocking Block Puzzles

    • Concurrency & Timing Puzzles section

    Previous

    75 / 293

    Next: input #0 vs input #1step Snapshot

    Up next

    Up nextinput #0 vs input #1step Snapshot

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Why Every Sample Is One Cycle Old
    • Nonzero Input Skew Looks Back in Time
    • Mixing Direct Drive and cb Drive