Use global variable across tasks?

Hi,

I have a global variable x, which is being assigned in task A. I want to use the value of this assigned variable in task C.

Example:

bit x;

fork
task A
task B
task C
task D
join_none

task A()
{
assign x = (some value or calculation here);
}

task C()
{
assign cov_h.x = x (want to use the value 'x' assigned in task A)
}

How do I make sure that value of x is assigned in task A before using it in task C? What is the best optimal approach or any other approach to resolve this?

Thank you

Using a shared global variable across concurrent threads is not a good programming practice. Sometimes you can look for a change in the variable’s value, but that won’t work if the new value being written is the same as the current value. There are also race conditions when the change happens before you begin waiting for it.

The preferred mechanism is the built-in mailbox#(bit) class using put() and get() methods to synchronize between two threads. There may be other mechanisms when you have more than two threads. The UVM includes many of these for different situations.

Hi @akmehta2802

As @dave_59 said, it is best to use mailboxes to exchage information between multiple threads.

However, you can also use events. Trigger an event in task A once assignment is done (using ->> operator; if you wish to use -> operator then I’ll suggest to use wait(event.triggered) call to wait for an event to be triggered in task C) and waits for that event to be triggered (using @ operator) in task C before using the value of x.

Small piece of code:

module automatic top;
  int x, y, z;
  event e1;
  task A(input int a, output int b = x);
     b = a + 10;
     ->>e1;
  endtask
  
   task B(input int a, output int b = y);
      b = a;
   endtask

   task C(input int a, output int b = z);
      @e1;
       b = a + x;
   endtask

   initial begin
      fork
         C(12);
         B(11);
         A(10);
      join_none
      wait fork;
      $display("X: %0d, Y: %0d, Z: %0d", x, y, z);
   end
endmodule

Output:

# X: 20, Y: 11, Z: 32

As expected, the output of Z is 32 because x (which is assigned in task A has been used).

Hope it helps you.

Thanks,
Naveen Kadian

Thanks for the replies.

However, I was wondering if it’s better to use wait(event.triggered) in task C to avoid race condition?

It’s better to use the mailbox. Regarless of whether you use the -> or ->> trigger, it has to come in the same time step when you begin waiting for it.

1 Like

Hi Dave,

I wanted to understand what could go wrong with events?

In the example Naveen showed above, if we trigger the event e1, ‘b’ will have the updated value and we can use that in task C, I assume. Can there still be a potential race condition?

The examples we’ve seen so far all take place with no delays at time 0. That is not realistic usage of fork/tasks. What happens if there were some delays before waiting for the event e1? You cannot wait for events in the past. A mailbox avoids this issue.

1 Like