systemverilog在for循环中使用fork

我想在一个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线程。

(0)

相关推荐