The wait fork suspends the parent sequence (or test) until all the child sequences (processes) have completed. There reason you can’t just use fork/join is because of the outer for_loop used to spawn each sequence (process) with a fork statement. If you used a fork/join, then each iteration of the loop would be blocked until the sequence completed, and the fork/join is not really doing anything different than a begin/end.
Thanks Dave. I am afraid i still dont fully understand the usage of wait fork here. :(
I copied your code below, I understand that using fork/join_none inside of for-loop, and using fork/join(first line and last line of your code) to wait all threads created by for-loop to be completed, but i dont understand why there is still a wait fork statement befor join, does the fork/join ( first line and last line of your code ) already wait for all threads to be completed?
thank you
fork
begin : isolating_thread
for(int index=0;index<14;index++)begin : for_loop
fork
automatic int idx=index;
begin
`ovm_do_on(sequence_inst,p_sequencer.my_sqr[idx]);
end
join_none;
end : for_loop
wait fork;
end : isolating_thread
join
A fork/join blocks until all direct child threads to complete. A fork/join block does not wait for its grandchildren threads to complete unless a child thread is blocked waiting for a grandchild thread.
In the example above there is only one child thread of the outerfork/join, the isolating_thread begin/end block. Without the wait fork statement, the isolating_thread would not block waiting for the grandchildren threads spawned by the fork/join_none inside the for loop.
Now the reason for the outer fork/join block is a bit trickier to explain, since we are only showing a fragment of code.
The wait fork statement blocks until all child threads of the current parent thread complete. We do not know if there were any other fork/join_none statements that came before this code snippet that we do not want to wait for, The isolating thread creates thread layer that guarantees that we only block waiting for the child threads of the isolating_thread.
In these examples, the automatic variable is declared before the fork. In most other examples I have seen it inside the Fork. Are both equivalent? Before forking feels as if the variable isn’t really belonging to the forked thread?
You are correct. There needs to be a separate idx variable for each invocation of the fork/join_none. I overlooked this since it was not the main point of the original question. I have edited the example.
Is it possible to do something similar, but accomplish join_any behavior instead of join_all? All examples that I have seen on this topic always use the “wait fork” statement.
I am interested in starting multiple threads in parallel and joining them when just one completes. In particular, I want to wait for just one of any events to occur. I have tried a few variations of the following example, but without success.
Any help would be greatly appreciated. Thanks!
JH
fork
begin
foreach(my_cbs[i]) begin // loop through an array of callbacks
fork
automatic int var_i = i;
begin
@(my_cbs[var_i].change_event); // wait for an event triggered within the callback
end
join_none
end
end
join_any
begin
event just_one_of any;
foreach(my_cbs[i]) // loop through an array of callbacks
fork
int var_i = i;
begin
@(my_cbs[var_i].change_event); // wait for an event triggered within the callback
-> just_one_of_any;
end
join_none
@just_one_of_any;
end
If I have two for-loop, how to handle it ? Is below code correct ?
fork
begin : isolating_thread
for(int index=0;index<14;index++)begin : for_loop
fork
automatic int idx=index;
for(int j=0;j<14;j++)begin
automatic int jdx=j;
begin
`ovm_do_on(sequence_inst,p_sequencer.my_sqr[idx][jdx]);
end
join_none;
end : for_loop
wait fork;
end
end : isolating_thread
join
In reply to dave_59:
Hi Dave,
If I have two for-loop, how to handle it ? Is below code correct ?
fork
begin : isolating_thread
for(int index=0;index<14;index++)begin : for_loop
fork
automatic int idx=index;
for(int j=0;j<14;j++)begin
automatic int jdx=j;
begin
`ovm_do_on(sequence_inst,p_sequencer.my_sqr[idx][jdx]);
end
join_none;
end : for_loop
wait fork;
end
end : isolating_thread
join
That should work, not sure you need that second automatic variable assignment for j, but it shouldn’t hurt.
I just ran into this problem yesterday… great thread… I totally missed the part about the automatic variable for the fork.
Is there any different between below two snippet of code ? (The different code is pointed out with comment)
I have thread_A() which is an isolated thread, and thread_B(i) which is parameterized with forloop variable, and another thread_C() in my code. I want all thread_B(i) are spawned in parallel and start the thread_C() when all of them finished. and above process is regarded as a whole thread, and run with thread_A in parallel. One of them finished then disable all others.
fork
thread_A();
begin
fork // here is difference
for (int i = 0; i < 8; i++) begin
fork
automatic int j = i;
thread_B(j);
join_none
end
wait fork;
join // here is difference
thread_C();
end
join_any
disable fork;
fork
thread_A();
begin
for (int i = 0; i < 8; i++) begin
fork
automatic int j = i;
thread_B(j);
join_none
end
wait fork;
thread_C();
end
join_any
disable fork;
The wait fork waits for all child processes of the current thread to terminate. In your first example, any process created by thread_A are cousins, not children of the current thread. In your second example, any process created by thread_A are children of the current thread.