我想在一个for循环中fork_join或者fork_join_none语句实现多线程, 假如我使用经典的方法:
for(int index=0;index<14;index++)begin
automatic int idx=index;
fork
begin
`uvm_do_on(sequence_inst,p_sequencer.my_sqr[idx]);
end
join_none;
end
上图中例子是正常工作的写法,假如我用fork_join替代fork / join_none会发生什么呢?当然是sequence一个个顺序执行,而没有实现并行。
为什么会发生这样的情况呢?看起来fork_join打破的sequence的并行执行。这就牵涉到fork_join, fork / join_none和fork / join_any的区别了。
如下图所示:
- fork / join: 父线程被阻塞,直到这个分支产生的所有子线程完成。即在执行statement4之前fork_join语句中的其他3个statement必须完成。
- fork / join_any: 父线程被阻塞,直到由此分支产生的任何一个线程完成。即在执行statement4之前fork / join_any语句中的其他3个statement必须有一个完成。
- fork / join_none: 父线程继续与fork产生的所有子线程同时执行。 生成的子线程不会开始执行,直到父线程执行阻塞语句或终止。即fork / join_none语句中3个statement被queued, statement4执行。
下面我主要就fork_join和fork_join_none的区别加以说明。
因为fork / join是一个阻塞语句,所以只有fork / join中的语句并行执行。我们需要做的是在for循环之后添加一个wait_fork语句。 这会阻止当前线程,直到所有子线程完成。 如果有其他更早的fork_join_none语句不需要等待它们完成,那么必须小心。 如果有的话,你需要创建一个隔离线程。
示例如下:
fork
begin : isolating_thread
for(int index=0;index<14;index++)begin : for_loop
fork
int idx=index;
begin
`ovm_do_on(sequence_inst,p_sequencer.my_sqr[idx]);
end
join_none;
end : for_loop
wait fork;
end : isolating_thread
join
上例中的wait fork暂停了父sequence的执行,直到所以子sequence执行完成。之所以不能使用fork / join,因为外部的for循环用fork语句产生每个序列(过程)。如果使用了fork / join,那么循环的每次迭代都会被阻塞,直到sequence完成,那么fork / join实际上和begin / end并没有什么不同。
或许你会疑惑为什么在join之前仍然有一个wait fork语句,fork / join(代码的第一行和最后一行)是否已经等待所有线程完成?
事实上是这样的,一个fork / join将阻塞,直到所有的直接子线程完成。 一个fork / join块不会等待它的grandchild线程完成,除非子线程被阻塞,等待一个grandchild线程。在上面的例子中,外部fork / join中只有一个子线程,即isolating_thread begin / end块。 如果没有wait fork语句,那么isolating_thread不会阻塞在for循环中等待由fork / join_none产生的grandchild线程。