为何含嵌套fork-join_none的automatic task中inout参数输出为0?
为什么automatic任务嵌套fork-join_none使用inout参数时输出为0?
先明确两种风格的核心差异,再拆解原因:
两种风格的代码示例
风格1(输出3)
module test; initial begin fork automatic int x = 0; sum(x); #15 $display("Style1: x = %0d", x); join_none end automatic task sum(inout int val); val = 1 + 2; // 直接在任务主流程赋值 endtask endmodule
风格2(输出0)
module test; initial begin fork automatic int x = 0; sum(x); #15 $display("Style2: x = %0d", x); join_none end automatic task sum(inout int val); fork val = 1 + 2; // 在任务内部的fork-join_none里赋值 join_none endtask endmodule
关键原因拆解
automatic任务的inout参数规则
调用automatic任务时,实参会先复制到任务的形参(这是属于当前任务调用的局部自动变量);只有当任务的主流程执行完毕时,形参的当前值才会写回给实参。风格2的执行时序
- 调用
sum(x)时,实参x的0被复制到任务形参val。 - 任务内部的
fork-join_none会创建一个异步子线程,但任务的主流程不会等待这个子线程执行,直接走到任务结束。 - 任务结束时,形参
val还是初始的0,所以把0写回给实参x。 - 之后子线程才会执行
val = 1 + 2,但此时任务已经结束,形参val作为automatic任务的局部变量,生命周期已经结束,这个赋值对实参x没有任何影响——实参已经被任务结束时的0覆盖,而且形参的副本已经被销毁。 - 延迟15个时间单位后打印
x,结果就是0。
- 调用
风格1为什么正常
风格1中,任务主流程直接执行val = 1 + 2,形参val变成3,任务结束时把3写回实参x,所以延迟打印能得到预期的3。
额外注意点
fork-join_none的本质是启动子线程后立即继续当前流程,不会等待子线程完成。- automatic任务的局部变量(包括inout形参)的生命周期绑定到任务的主流程,主流程结束,变量就被释放,子线程后续对这些变量的操作都是无效的(甚至可能触发未定义行为)。
内容的提问来源于stack exchange,提问作者Gayathri Hariharakrishnan
相关产品推荐
相关产品推荐

