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
    • Semaphore & Mailbox Puzzles
      • Lock Held Across Blocking Response Wait
      • Bounded Mailbox put Deadlock
      • try_get Busy Spin at Time 0
      • Leaked Semaphore Token on Error Path
      • Two Consumers Waiting on One Mailbox
      • Deadlock-Free Request Loop with try_put/try_get
    • 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

←Semaphore & Mailbox Puzzles
  1. Topics
  2. DV Interview Puzzles
  3. Concurrency & Timing Puzzles
  4. Semaphore & Mailbox Puzzles
  5. Deadlock-Free Request Loop with try_put/try_get
On this page

    VLSI DV Interview PuzzlesAll levels

    Deadlock-Free Request Loop with try_put/try_get

    Does this pattern avoid deadlock? What time does it print, and what does the bounded retry change if the consumer never answers?

    Puzzle

    Difficulty: Medium · Puzzle 6 of 6 · Topic: Semaphore & Mailbox Puzzles

    Does this pattern avoid deadlock? What time does it print, and what does the bounded retry change if the consumer never answers?

    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
    30
    31
    32
    33
    34
    `timescale 1ns/1ps
    module tb;
      mailbox #(int) req_mb = new(2);
      mailbox #(int) rsp_mb = new(2);
    
      task automatic producer();
        int rsp;
        int tries = 0;
        while (!req_mb.try_put(7)) #1;
        while (!rsp_mb.try_get(rsp)) begin
          #1;
          if (++tries == 5) begin
            $display("[%0.1f] producer: no response after 5 retries", $realtime);
            return;
          end
        end
        $display("[%0.1f] rsp=%0d", $realtime, rsp);
      endtask
    
      task automatic consumer();
        int req;
        #0.5;
        while (!req_mb.try_get(req)) #1;
        rsp_mb.put(req + 1);
      endtask
    
      initial begin
        fork
          producer();
          consumer();
        join
        $finish;
      end
    endmodule

    Hint

    No thread holds anything while it waits, and every wait is a time delay.

    Step-by-step solution

    Diagram
    1) The producer's try_put succeeds at t=0; its first try_get fails, so it backs off #1.
    2) The consumer starts at t=0.5 (explicit delay, so the order is deterministic), try_get gets 7, and rsp_mb.put(8) completes at once.
    3) At t=1.0 the producer's try_get returns 8 and prints [1.0] rsp=8. Same result with the fork order swapped (verified in Verilator).
    4) There is no circular wait. Without the consumer (removed in a test) the producer gives up and prints '[5.0] producer: no response after 5 retries' instead of spinning forever.

    Answer

    Answer: Yes, it is deadlock-free. It prints [1.0] rsp=8. The retry bound turns a missing peer into a clean report at t=5 instead of an endless polling loop.

    How this was checked

    Checked by running the code in Verilator 5; the printed output supports the answer above. No thread holds anything while waiting, so the request/response finishes at t=1.0. If nobody answers, the retry bound reports at t=5.0 instead of spinning forever.

    Why candidates get it wrong

    Deadlock-free is not livelock-free: an unbounded poll-with-#1 loop never hangs a time step, but it never ends either if the peer is dead, which is why the retry bound reports at t=5.0. Nothing is held while waiting, so no lock is needed here.

    Interviewer follow-up

    What timeout and error-report strategy would you add for regression triage? Model answer: bound by simulation time (a watchdog or timeout fork), report with `uvm_error` including the mailbox name and last request, and kill/disable the poller so the test fails fast instead of hitting the global timeout.

    Say it out loud

    Yes, it avoids deadlock, and it prints rsp equal to 8 at time one. The producer's first try_get fails and it backs off, the consumer starts at point five and answers at once, and there is no circular wait because nothing is held while waiting. The retry bound is the other half: if the consumer never answers, it reports at time five instead of polling forever. The trap is mixing up deadlock-free and livelock-free, so I would check what the bounded loop does when the peer is dead.

    Related topics

    • Mailboxes: Typed Pipes with Backpressure

    • Synchronization Patterns: Handshakes, Phasing and Objections

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

    • Back to Semaphore & Mailbox Puzzles

    • Concurrency & Timing Puzzles section

    Previous

    84 / 293

    Next: Concurrency & Timing Puzzles: Tricky Q&A

    Up next

    Up nextConcurrency & Timing Puzzles: Tricky Q&A

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Lock Held Across Blocking Response Wait
    • Bounded Mailbox put Deadlock
    • try_get Busy Spin at Time 0