2013-01-11 38 views
6

我有類似下面的僞代碼的東西:正確使用「禁用叉」的

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 

從代碼:只有輸入可以打破叉的應用,因爲其他兩個線程都同時下工作(1 ) 我想要的每個迭代之間禁用所有線程,即,一旦被施加輸入的流 - 禁用所有產生的線程,直到下一次迭代開始(用新的配置)

所以我修改上面的代碼

.... 
join_any 
disable_fork 
end 

但是,這似乎禁用循環以及/或類似的東西,我不明白,但效果是測試掛了。 有人可以解釋我的理由和解決方案嗎?

+0

這可能會變成一個沒有用的問題:在禁用fork之後,我沒有釋放信號量,從而導致沒有更多事務。我目前正在調試將在以後更新 – wisemonkey

+0

你想完成什麼?你確定你需要一個平行塊嗎? – 2013-01-14 01:04:52

+0

Thanks @ Adam12是的,這些塊需要並行,這是我需要驗證功能的方式。我正在嘗試驗證在更新期間是否讀取正在進行的特定寄存器提供的有效數據。是的,這個問題是因爲我沒有釋放信號量。我已經解決它,現在它的工作正常 – wisemonkey

回答

18

「禁用fork」不僅會殺死您的fork ... join_any啓動的進程,還會殺死執行禁用fork的同一進程的後代的任何其他進程。如果您在此流程的生命週期中早些時候啓動了其他任何進程(例如使用fork ... join_none),那麼其他進程也將被終止。

您可以通過使您的fork ... join_any及其後來的禁用fork在其自己的新子進程中運行來避免此問題。這限制了禁用叉的影響,因此它只能影響您關心的新啓動的進程,並且保證沒有其他不需要的影響。

在封閉全亂做這個「叉開始......最終加盟」是這樣的:

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 

這是一個衆所周知的問題,用叉子... join_any和叉... join_none 。最近在Verification Guild論壇上討論過,在Sutherland and Mills的書「Verilog and 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)語言結構做同樣的事情。

+0

謝謝,這更有意義。到目前爲止,在我的測試中只有一個分支,所以我的方法正在工作,但我正在將它們改爲您提出的將它們與未來更改隔離的方法。我同意你的觀點,在我習慣了正確的方法之前,我將不會使用定義。 – wisemonkey

0

禁用叉應該工作正常。這是一個小例子。

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 
+0

爲什麼它不會殺死所有其他線程? –

0

您應該考慮使用過程而不是禁用 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 
if (process1 != null && process1.status != process::FINISHED) 
    process1.kill(); 
if (process2 != null && process2.status != process::FINISHED) 
    process2.kill(); 

它應該是比禁止更安全。