Hi
I want to spawn multiple threads with each thread having an index input argument like
for (int i = 0;i < 5;i++) begin
fork
thread(i)
join_none
end
wait_fork;
But since i is a common variable for all threads, all threads are spawned with index 4.
I don’t want to use join_all as i want all threads to be spawned simultaneously.
What makes it work is that for each iteration of the for loop, a local automatic variable is created with a lifetime that is extended by the lifetime of the fork/join_none block that references it. The statements inside the fork/join_none block begin execution after finishing the for loop. It doesn’t mater if the function/task call passes its arguments by value or by reference; each call has an independent copy of the automatic variable that was set to a value as the for loop went through its iterations.
In reply to arun_ajs:
What makes it work is that for each iteration of the for loop, a local automatic variable is created with a lifetime that is extended by the lifetime of the fork/join_none block that references it. The statements inside the fork/join_none block begin execution after finishing the for loop. It doesn’t mater if the function/task call passes its arguments by value or by reference; each call has an independent copy of the automatic variable that was set to a value as the for loop went through its iterations.
I have a question here.
Lets say in the above example:
for(int i = 0; i < 5; i++) begin
automatic int j;
j = i;
fork
thread(j);
join_none
end
I made the following change:
for(int i = 0; i < 5; i++) begin
fork
automatic int j;
j = i;
thread(j);
join_none
end
This work fine too, but in case if I add begin-end around fork - join_none, it doesn’t work fine. Threads are spawned with 4.
Can you please what is the difference here.
In reply to ssubramaniam1990@gmail.com:
The change you show should not work, and introduces a race condition. You are now spawning two independent threads inside the fork/join_none. The two statements
j = i;
thread(j);
execute in parallel, so there is no guarantee that thread(j) gets the updated value of j. Also, the value of i at the point when j = i gets executed should be 5, for all iterations.
In reply to ssubramaniam1990@gmail.com:
The change you show should not work, and introduces a race condition. You are now spawning two independent threads inside the fork/join_none. The two statements
j = I;
thread(j);
execute in parallel, so there is no guarantee that thread(j) gets the updated value of j. Also, the value of i at the point when j = i gets executed should be 5, for all iterations.
Adding code tags:
Hi Dave,
You are right. I should have shown my code previously.
Here is my code:
program automatic fork_join;
initial begin
for(int i = 0; i < 16; I++)
begin
fork
// begin
int index =I ;
send(index);
// end
join_none
end
wait fork;
end
task send(int j);
temp();
$display("driving port %0d %t" , j, $realtime);
endtask // send
endprogram
I am trying 3 different cases:
Executing the above program, I can see the prints “Driving port 0-16”.
In the fork block doing something like this:
fork
// begin
int index ;
index = I ;
send(index);
// end
join_none
With this change Driving port 16 printed 16 times.
Adding begin-end around fork - join_none:
fork
begin
int index ;
index = I ;
send(index);
end
join_none
Again I see driving port16 being printed 16 times.
Can you please explain what is the difference between the 3 cases.
In reply to ssubramaniam1990@gmail.com:
The differences are in the lifetime of the variable index, and the timing of when that variable gets assigned with value of the variable i.
Realize that there will be 16 concurent variables named index and only one named i. In case 1) & 2), the index variable gets created upon each entry into the fork/join_none block. That occurs before spawning any process within the fork/join_none. In case 1) the variable initialization also occurs before any process within the fork/join_none. The thing that you need to remember is that automatic variables get created upon entry and initialized before executing any procedural statement within the block they are located in. So in case 1), each index variable gets the current value of i in each loop iteration.
In case 2), you moved the initialization into a separate procedural assignment statement. Each statement within a fork/join_none becomes as new child process and execution of the child process does not begin until the current parent thread suspends. The for loop now spawn 32 threads before suspending at the wait forkstatement when the value of i is 16. (and as I said before, it is a race if send(index) sees the unitialized value 0 or assigned value 16.
In case 3), the index variable is now declared inside a begin/end block, which is a single statement for the fork/join_none. So now the index variable does not get created until all 16 processes have been spawned, and the value of i is 16.
hello Dave sir, i got the concept what you have explained above but I have a small doubt
I have implemented the following code
module fork_test;
initial
begin
for (int j=0; j<3; j++)
begin
automatic int k=j;//(1)
fork
//automatic int k=j;//(2)
$display(k,$time );
join_none
end
end
endmodule
I got the result i=3 thrice … i would like to know as I have put condition on i in for loop that it should be less than 3 still why its coming i =3.
another thing is when i implements number (1) statement it display result 2,1,0 why in reverse order? while for(2) it comes in order 0,1,2. I have run this code in EDA tool cadence incisive 15.20
I also ran this code on EDA playground and did not see the results you are getting. However, the order the $display statements execute is indeterminate.
There is no “i” in your example. But if you meant you were displaying “j” inside the fork/join_none loops, then j would be 3 since the for loop would terminate before any statements within the fork/join_none starts executing. That’s the point of giving each iteration of the for loop a local copy of k.
sorry sir , my mistake it was “j” .thanku sir
…
for(j=0;j<3;j++)
as per i understand , for loop will be suspended whenever j exceeds 2 ie if j=3 loop suspended but if i will display j it will show 3 is it so sir.
Hello Dave,
While going through this informative post. I had a question related to lifetime of control variable of for-loop.
initial
begin
for(int j=1; j<=3; j++)
begin
fork
automatic int k = j;
#k $write($time,"k=%0d\n",k);
begin
automatic int m =j;
$display("m=%0d",m);
end
join_none
end
#100;
end
I want to understand the lifetime of j in this example. for-loop execution will get over at time zero and it will schedule 6 process which will spawn once simulator hit #100.
In above example j is available(m=j) irrespective of for-loop execution is over. Does that means j lifetime is also dependent on the process which are schedule while for-loop is executing ?