验证基础技巧记录(二)

1.为了保障作用域的明确,fork里面一定要使用begin-end格式。

测试灵感来自:你的 disable fork 用的对吗?_guard fork-CSDN博客

为了保障作用域的明确,fork里面一定要使用begin-end格式,(当然,实际上是fork里有多个begin-end而不都在一个begin-end中)

否则很容易出现disable fork杀不死其范围内所有子进程的问题。

实际上disable fork的范围是fork-join内的begin-end这么大的范围,额外的begin-end将被视为开辟了新的子线程。

举例:

`timescale 1ns/1ns
module thread_test;
  parameter TIME_OUT = 200;

  task automatic wait_for_time_out(int id);
    event el;
    begin
      fork : main_thread
        begin
          if (id == 0)
            fork
              begin
                #2;
                ->el;
              end
            join_none
        end

        fork : just_a_little
          begin
            $display("@%0t: %m: id=[%0d] entering thread", $time, id);
            #TIME_OUT;
            $display("@%0t: %m: id=[%0d] done", $time, id);
          end
        join_none

        @(el) begin
          $display("@%0t: disable id=[%0d] wait_for_time_out", $time, id);
          disable fork;
        end
      join_none
    end
  endtask

  initial begin
    wait_for_time_out(0); // Spawn thread 0
    wait_for_time_out(1); // Spawn thread 1
    wait_for_time_out(2); // Spawn thread 2
    #(TIME_OUT * 2) $display("@%0t: All done", $time);
  end

endmodule

输出:

# 00: thread_test.wait_for_time_out.main_thread.just_a_little: id=[2] entering thread
# 00: thread_test.wait_for_time_out.main_thread.just_a_little: id=[1] entering thread
# 00: thread_test.wait_for_time_out.main_thread.just_a_little: id=[0] entering thread
# 02: disable id=[0] wait_for_time_out
# 0200: thread_test.wait_for_time_out.main_thread.just_a_little: id=[2] done
# 0200: thread_test.wait_for_time_out.main_thread.just_a_little: id=[1] done
# 0400: All done
# 0600: thread_test.wait_for_time_out.main_thread: id=[2] wakeup
# 0600: thread_test.wait_for_time_out.main_thread: id=[1] wakeup
# 0600: thread_test.wait_for_time_out.main_thread: id=[0] wakeup

显然,wake相关语句因为使用额外的begin-end隔开所以没有被杀死。

而需要强调的是,在同一个begin-end内,如果继续嵌套begin-end,也无法被视为开辟新的子进程,而无法阻隔disable fork的影响。

此外,fork内部如果都不使用begin-end,这将使得每一个语句都被视为开辟子进程,而在这个基础上,有条件的disable fork将杀死不了其他进程。

所以最好还是加上begin-end以锁住fork-join的作用域。

2.禁用进程的好方法。

基于(1),设置event,再通过触发激活fork-begin-disable这种方式,比直接杀死某个被大量调用的同名线程要好得多,我个人认为那样做太危险了,应该慎重一些。

3.应该把自增之类的语句放在触发事件前而不是触发事件后,以避免繁琐的语句影响下一次触发;

*我认为如果需要多次计数的话就什么都不要打印比较好,其实用mailbox更好吧;

4.应该结合具体的情况使用@和wait,wait可以解决一部分竞态问题;

5.

posted @ 2025-06-22 20:47  NoNounknow  阅读(27)  评论(0)    收藏  举报