10

我有类似于以下伪代码的东西:

for (lets say 10 iterations)
begin
// Do some configuration changes
    fork
        begin
        ///apply input to design
        end
        begin
        while (1)
        /// at particular point update expected status / values
        end
        begin
        while (1)
        /// read status and verify with expected values
        end
    join_any
end

从代码:只有输入的应用程序才能打破分叉,因为其他2个线程正在工作,而(1)我想在每次迭代之间禁用所有线程,即一旦应用输入流-禁用所有产生的线程,直到下一次迭代开始(新配置)

所以我将上面的代码修改为

 ....
 join_any
 disable_fork
 end

然而,这似乎也禁用了 for 循环/或类似的东西,我不明白但效果是测试被挂起。有人可以解释一下原因和解决方案吗?

4

3 回答 3

29

“disable fork”不仅会杀死由你的 fork...join_any 启动的进程,还会杀死作为执行 disable-fork 的同一进程的后代的任何其他进程。如果您在该进程生命周期的早期启动了任何其他进程(例如,使用 fork...join_none),那么这些其他进程也将被终止。

您可以通过使您的 fork...join_any 及其后来的 disable-fork 在其自己的新子进程中运行来相当容易地防止这种情况发生。这限制了您的 disable-fork 的影响,因此它只能影响您关心的新启动的进程,并保证没有其他不需要的影响。

通过将整个混乱包含在“fork begin...end join”中来做到这一点,如下所示:

fork begin // isolate the following code as a single child process
  fork  // launch the processes you wish to manage
    apply_input();
    update_status();
    verify_status();
  join_any // kill off the *_status threads when apply_input terminates
  disable fork;
end join // end of child process isolation

这是 fork...join_any 和 fork...join_none 的一个众所周知的问题。最近在 Verification Guild 论坛上进行了讨论,并在 Sutherland 和 Mills 的书“Verilog 和 SystemVerilog Gotchas”的第 79 和第 80 节中进行了描述。

将“fork begin”和“end join”放在单行上是不寻常的,但我喜欢它作为一种非常明显的方式,即我正在同步分叉一个子进程。通常这将是无用的事情,但在这种情况下,这是必不可少的。

这个习语很常见,也很容易出错,你可能更喜欢将它封装在一对宏中(我不喜欢这个,但是......):

`define BEGIN_FIRST_OF fork begin fork
`define END_FIRST_OF join_any disable fork; end join

现在你可以写...

`BEGIN_FIRST_OF
    apply_input();
    update_status();
    verify_status();
`END_FIRST_OF

其中名称“...FIRST_OF”旨在反映与执行相同操作的 Specman (e) 语言结构的相似性。

于 2013-01-23T13:52:16.610 回答
2

您应该考虑在 SystemVerilog 中使用进程而不是禁用

process process1;
process process2;
fork
  begin
    process1 = process::self();
    # do something in process 1
  end
  begin
    process2 = process::self();
    # do something in process 2
  end
join_any
#1;
if (process1 != null && process1.status != process::FINISHED)
  process1.kill();
if (process2 != null && process2.status != process::FINISHED)
  process2.kill();

它应该比禁用更安全。

于 2018-01-24T16:41:08.667 回答
-1

禁用叉子应该可以正常工作。这是一个小例子。

 module top;

      initial
      begin
          $display(" BEFORE fork  time = %0t ",$time );

          for(int i = 0 ; i < 3 ; i++)
          begin
            fork
              automatic int j = i;
              begin
                  $display(" Action thread started time = %0t  j: %0d",$time,j);
                  #(10*j);
                  $display(" Action thread ended time = %0t  j: %0d",$time,j);
              end

              begin
                 $display(" Entered timeout_15 = %0t j: %0d",$time,j);
                 #15;
                 $display(" Ended timeout_15 = %0t j: %0d",$time,j);
              end
            join_any

            disable fork; // it kills all processes
            $display("---------------------------------------------------");
        end

       #100; // This is to make sure if there any threads ..

       $display(" time = %0d Outside the main fork ",$time );
       $display(" time = %0d  After wait fork ",$time );
      end
    endmodule

输出::

BEFORE fork  time = 0
 Action thread started time = 0  j: 0
 Entered timeout_15 = 0 j: 0
 Action thread ended time = 0  j: 0
---------------------------------------------------
 Action thread started time = 0  j: 1
 Entered timeout_15 = 0 j: 1
 Action thread ended time = 10  j: 1
---------------------------------------------------
 Action thread started time = 10  j: 2
 Entered timeout_15 = 10 j: 2
 Ended timeout_15 = 25 j: 2
---------------------------------------------------
 time = 125 Outside the main fork
 time = 125  After wait fork
于 2015-12-26T02:56:08.433 回答