Fork within loop with join ALL

In reply to aming:

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?

In reply to NiLu:

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

In reply to jhardy:

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

Thanks Dave! I appreciate the quick reply. Your suggestion solved my problem.

I assume that we still should declare the variable as automatic. Please correct correct me if I am wrong.

In reply to jhardy:
Yes. If this code is inside a class, then it is already automatic by default.

In reply to theketi:
i < 8 has to fail in order to end the loop. So i will be 8 after exiting the loop.

In reply to dave_59:

Hello Dave,
I am trying to run below code :


        my_seq = new[2];
        fork 
            begin : isolating_thread
              for(int index=0;index<2;index++) begin : for_loop
                  automatic int idx=index;
                  automatic int local_qd=$urandom_range(1,4);
                  fork
                      `uvm_do_with(my_seq[idx],
                                    {
                                     qd           == local_qd;
                                    })
                  join_none;
              end : for_loop
            wait fork;
            end : isolating_thread
        join

I am getting below Error :

=======================================================
Solver failed when solving following set of constraints
integer qd = 0;
integer local_qd = 4;
constraint WITH_CONSTRAINT // (from this) (constraint_mode = ON) (<File_path>:233)
{
(qd == local_qd);
}
=======================================================

Can you please help me with this ?? Thanks a lot in advance.

  • Biren

In reply to birenkumar:

This likely has nothing to do with a fork statement. Maybe you did not declare qd as rand.

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


In reply to zz8318:

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.

In reply to dave_59:

With respect to the fork and join ALL inside for loop, I have a very basic question regarding the same.


for (i = 0; i<3;i++) begin
    automatic int j = i;
    fork 
       $display(j);
    join
end

Will the output for the above code will be :
0
1
2
???

In reply to SanjanaDhiran:

A fork/join with one statement behaves just like a begin/end block as far as your example is concerned.

In reply to dave_59:

Hie Dave,
Thank you for responding. However, I am still a little confused. Will my output be :
0
1
2
??

In reply to SanjanaDhiran:

Are you able to try it your self? There is always www.edaplayground.com

In reply to dave_59:

Hi Dave,

I have a question here.

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;

In reply to zz8318:

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.

In reply to dave_59:

Hi Dave,

How to determine which thread is current thread ?

and which one is correct to meet the requirement I mentioned in my last post ?

In reply to zz8318:

By current thread I mean from the perspective of the thread executing the wait fork statement. You should have enough information to make the correct decision.