Cleaner way to kill a fork/join thread in SystemVerilog

Managing parallel threads is a common challenge in SystemVerilog testbenches. When you spawn threads using fork/join, fork/join_any, or fork/join_none, you often need to terminate them gracefully. This post covers three approaches, with a focus on the cleanest method using the process class.

Table of Contents


Method 1: Using process::self() and kill() (Recommended)

The process class in SystemVerilog provides a clean, object-oriented way to manage threads. This is the preferred approach in UVM environments and offers the most control.

process thread_handle;

// Spawn a thread
fork
  begin : worker_thread
    // Store handle to this process
    thread_handle = process::self();
    
    // Your tasks here
    drive_transaction();
    monitor_response();
  end
join_none

#0; // Allow the fork to start (important!)

// Later, when you need to kill the thread
wait(stop_condition);
if (thread_handle != null && thread_handle.status() != process::FINISHED)
  thread_handle.kill();

Key Points:

  • process::self() returns a handle to the current process
  • The #0 delay is critical for fork/join_none — without it, the thread may not start before you try to access the handle
  • kill() terminates the process and all its child processes
  • Always check status() before killing to avoid errors

Process Status Values

StatusDescription
process::FINISHEDProcess completed normally
process::RUNNINGProcess is currently executing
process::WAITINGProcess is waiting on a blocking statement
process::SUSPENDEDProcess is suspended
process::KILLEDProcess was terminated by kill()

Method 2: Using disable fork

The disable fork statement kills all child processes spawned by the current thread. It's simple but can be dangerous if not used carefully.

fork
  begin
    task_a();
  end
  begin
    task_b();
  end
join_none

#100ns;
disable fork; // Kills ALL child threads from this parent

Warning: disable fork affects all spawned threads from the calling process, not just the ones you might want to stop. This can cause unintended side effects in complex testbenches.


Method 3: Using disable with labels

You can disable a specific named block using its label. This is more targeted than disable fork.

fork
  begin : thread_A
    forever begin
      do_work_a();
    end
  end
  begin : thread_B
    forever begin
      do_work_b();
    end
  end
join_none

#500ns;
disable thread_A; // Only kills thread_A, thread_B continues

Limitation: The label must be visible in the current scope, which can be problematic in modular code.


Comparison Table

Method Precision UVM Compatible Scope Requirement Best For
process::kill() Single thread Yes Handle only UVM components, complex testbenches
disable fork All children Risky Current process Simple, isolated forks
disable label Named block Limited Label visibility Module-level threads

Best Practices

  1. Always use #0 after fork/join_none — This ensures the spawned thread gets a chance to execute and store its handle.
  2. Check process status before killing — Avoid calling kill() on already finished processes.
  3. Use process class in UVM — The UVM library uses this pattern internally (see uvm_sequence_base).
  4. Store handles in queues for multiple threads:
process thread_q[$];

for (int i = 0; i < 5; i++) begin
  fork
    automatic int idx = i;
    begin
      thread_q.push_back(process::self());
      worker_task(idx);
    end
  join_none
end
#0;

// Kill all threads later
foreach (thread_q[i]) begin
  if (thread_q[i].status() != process::FINISHED)
    thread_q[i].kill();
end

Conclusion

The process class provides the cleanest and most flexible way to manage thread lifecycles in SystemVerilog. It's the standard approach in UVM and gives you fine-grained control over individual threads without affecting others.

For more SystemVerilog tips, check out my other posts on SystemVerilog and UVM.

Author
Mayur Kubavat
VLSI Design and Verification Engineer sharing knowledge about SystemVerilog, UVM, and hardware verification methodologies.

Comments (0)

Leave a Comment