Fork_join

I was asked this question in an interview and I’m not understanding why the first piece of code prints ‘4’ four times and the second one prints “0,1,2,3” when automatic is used. Someone, please explain it to me. Thanks

code1:

module test1;
	int k;
	initial begin
		for(int i = 0; i<4; i++)begin
			fork
				k=i;
				$display(k);
			join_none
		end
	end
endmodule

Output:

4
4
4
4

Code 2:

module test1;
	initial begin
		for(int = 0; i<4 ; i++)begin
			fork
				automatic int k = i;
				$display(k);
			join_none
		end
	end
endmodule

Output:

0
1
2
3

In reply to sriharifoxtrot:

Two things you need to understand:

  1. Each statement inside a fork/join_none gets put into a new child thread that does not start until the parent thread blocks or terminates. In both code examples, that means after the initial block terminates. At that point, the for-loop has already finished and the variable
    i
    has the value 4. But in code 1, there are two statements that get forked into a total of 8 threads. They are all in a race, so if the
    $display(k);
    executes first, the output would be 0. Since there is only one shared static variable
    k
    , once the assignment
    k = i
    occurs, the $displays that execute after that will all display 4.
  2. Automatic variables get created and initialized upon entry into a procedural block (begin, fork, task or function). Each entry into the block creates a new variable. In the code 2 example, 4 different
    k
    variables get created and initialized each time through the loop with the current value of
    i
    . You would get the same behavior if you placed the declaration of
    k
    outside the fork, but inside the inner most begin/end block.

In reply to dave_59:

Thanks, Dave. That clears things up for me.

In reply to nimitz_class:

I was asked this question in an interview and I’m not understanding why the first piece of code prints ‘4’ four times and the second one prints “0,1,2,3” when automatic is used. Someone, please explain it to me. Thanks
code1:

module test1;
int k;
initial begin
for(int i = 0; i<4; i++)begin
fork
k=i;
$display(k);
join_none
end
end
endmodule

Output:
4
4
4
4
Code 2:

module test1;
initial begin
for(int = 0; i<4 ; i++)begin
fork
automatic int k = i;
$display(k);
join_none
end
end
endmodule

Output:
0
1
2
3

In the above code 2, if I were to write the fork-join_none in this way, it wouldn’t work.
fork
begin
automatic int k = i;
$display(k);
end
join_none

Why is that? Why does the assignment of k have to be a separate parallel thread to the display function call?

In reply to nikhilac@nvidia.com:

Dave’s answer (point 2) answers your question :

From the compiler’s POV, you are inside the “for” loop, and the “procedural block” is the fork statement.
When you use a “begin” inside the fork, it’s another “procedural block” under the fork, and that’s where the compiler stops looking.


fork
  begin : new_block
    automatic int k = i;
    $display(k);
  end
join_none

In other words, the “automatic int k = i” belongs to “new_block” and not to the “fork block”. The assignment only happens after all the 4 forks have spawned, at which point i is already 4.