fork join
在systemverilog中可以用fork…… join
、fork ……join_any
、fork……join_none
来实现多个线程的并发执行。
1、父线程、子线程
调用fork……join
的线程为父线程,fork……join
中并发执行的是子线程,子线程可有多个,父线程只有一个。
无延时情况下竞争问题:
- 无延时情况下,主线程无延时语句优先于子线程无延时语句先执行
- 无延时优先于#0(零延时),无延时语句优先于零延时语句先执行。
2、阻塞父线程
2.1 fork-join
调用fork……join
会阻塞父线程,直到子线程全部结束,才会启动父线程。
program test;
initial begin
fork
$display("child"); // fork下的子线程,并发执行
$display("child"); // fork下的子线程,并发执行
$display("child"); // fork下的子线程,并发执行
#0 $display("child"); // fork下的子线程,并发执行
join
$display("father"); // begin块下的父线程,顺序执行
$display("father"); // begin块下的父线程,顺序执行
$display("father"); // begin块下的父线程,顺序执行
#0 $display("father"); // begin块下的父线程,顺序执行
end
endprogram
fork……join
中有4个子线程,要执行完4个子线程后才会执行父线程,输出为:
2.2 fork-join_any
fork……join_any
也会阻塞父线程,不过任意一个子线程结束后就执行父线程,且当父线程执行完所有的无延时语句后才会把权限交给子线程。遇到# N
延时语句后子线程与父线程开始竞争。父线程有优先权,当父线程有权限后会优先执行完所有无延时语句,才会让子线程执行无延时语句。有延时语句父线程和子线程公开竞争。
program test;
initial begin
fork
$display("child"); // fork下的子线程,并发执行
$display("child"); // fork下的子线程,并发执行
$display("child"); // fork下的子线程,并发执行
#0 $display("child"); // fork下的子线程,并发执行
join_any
$display("father"); // begin块下的父线程,顺序执行
$display("father"); // begin块下的父线程,顺序执行
$display("father"); // begin块下的父线程,顺序执行
#0 $display("father"); // begin块下的父线程,顺序执行
end
endprogram
fork join_none
fork……join_none
不会阻塞父线程,且执行完父线程无延时的语句后才会将权限交给子线程。遇到# N
的延时语句后,子线程与父线程开始竞争。父线程有优先权,当父线程有权限后会优先执行完所有无延时语句,才会让子线程执行无延时语句。有延时语句父线程和子线程公开竞争。
program test;
initial begin
fork
$display("child"); // fork下的子线程,并发执行
$display("child"); // fork下的子线程,并发执行
$display("child"); // fork下的子线程,并发执行
#0 $display("child"); // fork下的子线程,并发执行
join_none
$display("father"); // begin块下的父线程,顺序执行
$display("father"); // begin块下的父线程,顺序执行
$display("father"); // begin块下的父线程,顺序执行
#0 $display("father"); // begin块下的父线程,顺序执行
end
endprogram
3、结束子线程
3.1 disable lable
disable lable
结束lable所指定的线程和子线程。(可以结束fork,也可以结束begin)如果fork块进入多次,用disalbe lable的方式会结束所有的进程。比如一个task中有fork块,这个task调用多次,如果task中的某一次调用执行了disalbe语句,会disalbe掉多次调用的产生的所有线程。
program test;
initial begin
fork:fork1
$display("child"); // fork下的子线程,并发执行
$display("child"); // fork下的子线程,并发执行
$display("child"); // fork下的子线程,并发执行
#0 $display("child"); // fork下的子线程,并发执行
fork
$display("child");
join
join_none
fork:fork2
$display("child21");
fork
#2 $dipslay("child22");
join
#2 display("child23");
join_none
#1 disable fork2; // 1ns后,结束fork2下的子线程
$display("father"); // begin块下的父线程,顺序执行
$display("father"); // begin块下的父线程,顺序执行
$display("father"); // begin块下的父线程,顺序执行
#0 $display("father"); // begin块下的父线程,顺序执行
end
endprogram
3.2 disable fork
disable fork
语句会结束disable fork
所在进程所生成出的所以子线程,及子线程的子线程。
program test;
initial begin
fork:fork1
$display("child"); // fork下的子线程,并发执行
#2 $display("child"); // fork下的子线程,并发执行
#2 $display("child"); // fork下的子线程,并发执行
#2 $display("child"); // fork下的子线程,并发执行
fork
#2 $display("child");
join
join_none
fork:fork2
$display("child21");
fork
#2 $dipslay("child22");
join
#2 display("child23");
join_none
#1 disable fork; // 1ns后,结束fork1和fork2下的子线程。
$display("father"); // begin块下的父线程,顺序执行
$display("father"); // begin块下的父线程,顺序执行
$display("father"); // begin块下的父线程,顺序执行
#0 $display("father"); // begin块下的父线程,顺序执行
end
endprogram
4、等待进程结束
wait fork
等待当前线程的所以子线程结束(不包括子线程的子线程。)
program automatic test;
initial begin
fork
#99 $display("#99"); // 等待这个子线程
fork
#100 $display("#100"); // 不等待子线程的子线程
join_none
joine_none
wait fork;
$display("after waite");
end
endprogram
5、for-fork:多线程的变量问题
1、copy变量应该在fork内,且copy给automatic变量,线程例化后,先初始化这些变量后再例化其他线程。
2、for-fork有变种,比如function中有fork,for来调用function
class cbk;
task run();
for(int i=0; i<10; i++)begin
fork
int j = i; // class 中的都是默认是automatic变量
begin
#10ns;
$display(j);
end
join_none
end
endtask
endclass
标签:fork,begin,join,sv,线程,执行,display
From: https://www.cnblogs.com/yuandonghua/p/17727266.html