SystemVerilog, a powerful hardware description and verification language, introduces advanced constructs to manage parallel processes effectively. Among these, fork-join, fork-join_any, and fork-join_none are pivotal for controlling multiple threads. This article delves into these constructs, explaining their behavior with practical examples.
What is Fork-Join?
fork-join is used to execute multiple processes in parallel. All threads within the fork-join block must complete before the program continues execution beyond the block.
Syntax:
fork
<thread1>;
<thread2>;
...
join

In fork_join, once all the processes inside the block will be completed, only after that it will come out of the block.
Example:
module fork_join_example;
initial begin
$display("Start of execution");
fork
$display("Thread 1 started");
#5 $display("Thread 2 started after 5 time units");
#10 $display("Thread 3 started after 10 time units");
join
$display("End of execution");
end
endmodule
Output:
Start of execution
Thread 1 started
Thread 2 started after 5 time units
Thread 3 started after 10 time units
End of execution
In this example, the simulation waits for all three threads to complete before moving to the final statement.
What is Fork-Join_Any?
fork-join_any enables parallel execution of multiple threads but continues execution as soon as any one thread completes. It’s ideal for scenarios where the result from one thread is sufficient to proceed.
Syntax:
fork
<thread1>;
<thread2>;
...
join_any

In fork-join_any, if any of the processes inside the block will be completed, it will come out of the block. In this case, 5 time unit process will be completed first.
Example:
module fork_join_any_example;
initial begin
$display("Start of execution");
fork
begin
#5 $display("Thread 1 completed");
end
begin
#10 $display("Thread 2 completed");
end
join_any
$display("One thread has completed, continuing execution");
end
endmodule
Output:
Start of execution
Thread 1 completed
One thread has completed, continuing execution
Thread 2 completed
Here, the program doesn’t wait for both threads to finish; it proceeds as soon as the first thread completes.
What is Fork-Join_None?
fork-join_none begins executing threads in parallel and immediately continues to the next statement without waiting for any thread to complete. This is useful for tasks that need to run in the background.
Syntax:
fork
<thread1>;
<thread2>;
...
join_none

In fork-join_none, it will start executing threads in parallel and won’t wait for any thread to be completed.
Example:
module fork_join_none_example;
initial begin
$display("Start of execution");
fork
begin
#5 $display("Thread 1 completed");
end
begin
#10 $display("Thread 2 completed");
end
join_none
$display("Continuing execution without waiting for threads");
end
endmodule
Output:
Start of execution
Continuing execution without waiting for threads
Thread 1 completed
Thread 2 completed
In this case, the program doesn’t wait for any thread; it moves on immediately after starting the threads.
The one thing here is to notice that once it comes after the fork block, after executing the display statement it again goes to fork block to complete all the remaining process.
Comparison Table
| Construct | Behavior |
|---|---|
fork-join | Waits for all threads to complete before continuing. |
fork-join_any | Waits for any one thread to complete before continuing. |
fork-join_none | Continues immediately without waiting for any thread to complete. |
Use Cases
fork-join: Best for tasks requiring synchronization, where all threads must finish before proceeding.fork-join_any: Ideal for scenarios where the output from the first completed thread suffices.fork-join_none: Useful for launching background tasks or non-critical processes.