目录
for-join_none并行
for循环
和fork-join_none
语句可以组合使用来并行执行多个块,这里必须使用非阻塞的fork-join_none
来启动多线程,因为使用fork-join_none
时每一次循环都会创建新的fork块,并且不影响之后创建fork块,而fork-join
则会阻塞后面的fork块的执行,主要是保证fork块内的线程并行执行。但其实在使用for-join_none
并行执行时,很容易出现错误情况,下面先描述一种常见错误情况。
program no_auto;
initial begin
for(int j=0;j<3;j++)
fork
$write(j);
join_none
#0 $display("\n");
end
endprogram
上面代码本意时每个线程依次打印0,1,2
,但在执行线程前需要在#0时延之前计算完成。因此依次执行下面代码
j=0
创建write(j)——线程0,创建不执行j=1
创建write(j)——线程1,-创建不执行j=2
创建write(j)——线程2,-创建不执行- 在
#0
执行消耗时间前,多线程同时执行 j=2
执行write(j)——线程0j=2
执行write(j)——线程1j=2
执行write(j)——线程2$display("\n")
——主线程执行
而由于多线程之间使用的时同一个变量,则导致线程0、1、2打印的都为j=2
.
因此为了避免这种错误,可以使用自动变量来保存变量的拷贝,之后每一个线程都会创建自动变量k
并保存一次j
的值,#0
之后三个线程将打印出其拷贝值k
,而不再是共同且唯一的变量j。
program no_auto;
initial begin
for(int j=0;j<3;j++)
//当然也可以放在这里
//automatic int k=j;
fork
automatic int k=j;
$write(k);
join_none
#0 $display("\n");
end
endprogram
当然如果代码是在automatic
类型的代码或者模块里面,那么声明时可以不适用关键词automatic声明变量,而是可以直接在循环中使用变量,即可自动在每个线程中创建变量。
program automatic auto;//通过指定代码块为自动变量存储,此时在for循环中的k
initial begin //在每一次循环中都会给定不同的存储空,此时多次调用
for(int j=0;j<3;j++)//将不会存在问题
int k=j;
fork
$write(k);
join_none
#0 $display("\n");
end
endprogram
但在UVM中是不是需要必须指明
automatic
代码块呢?
答案是不一定的,因为SV中的class的方法就默认是automatic
模式,因此不需要特别的在fork
前面的外部自动变量做automatic int k=j
的声明,直接按照变量声明即可int k=j
,但为保证含义清晰,最好添加上automatic
。
foreach并行
foreach相比于for循环,其需要输入数组变量,foreach(变量[迭代器]]),输入变量少,而且可以更方便的迭代。常见用法包括可以在UVM环境中将并行启动多个seqence,将seqence同时发送到多个agent上。
begin : foreach_fork
seq_class seq [`CONST];
foreach(env.agt[i])
begin
automatic int j = i;
seq[j] = seq_class::type_id::create
(.name($sformatf("seq_%0d", j)), .contxt(get_full_name()));
fork
begin
seq[j].start(env.agt[j].sqr);
end
join_none // non-blocking thread
end
wait fork; //等待
end : foreach_fork
具体执行过程如下:
foreach
循环遍历每一个env.agt集合的每个代理。automatic int j = i;
创建为唯一的索引,对于避免并发问题,这里相当重要,由于这里是类的方法,所以可以不加automatic
而单纯是int j=1
,并创建对应的sequence.- 使用
fork-join_none
进行并行化启动,此在fork-join_none中新线程来并执行其中的代码块,此关键字指示仿真器继续执行,而无需等待已经启动的线程完成,这允许循环继续迭代并为其他代理启动新线程。 seq.start(env.agt[j].sqr)
:此行使用sequence在env.agt[j].sqr上启动。wait fork
:所有线程启动完成之后,并在此行之前同时执行。此语句使主线程等待,直到所有先前fork的线程(来自foreach)完成执行,这确保所有线程的sequence发送完成。
标签:fork,none,join,并行执行,线程,foreach,automatic,systemverilog From: https://www.cnblogs.com/nullbeer/p/18342384参考文献
[1]How can I use foreach and fork together to do something in parallel?
[2] 【system verilog】fork-join_none与循环语句共同使用的行为探究_fork join none-CSDN博客
[3] 绿皮书