SystemVerilog: fork-join_none Gotcha - IKSciting
2052
post-template-default,single,single-post,postid-2052,single-format-standard,bridge-core-2.8.7,qodef-qi--no-touch,qi-addons-for-elementor-1.7.1,qode-page-transition-enabled,ajax_fade,page_not_loaded,,qode-title-hidden,qode_grid_1300,footer_responsive_adv,qode-content-sidebar-responsive,qode-theme-ver-27.1,qode-theme-bridge,qode_header_in_grid,wpb-js-composer js-comp-ver-6.6.0,vc_responsive,elementor-default,elementor-kit-838

fork-join_none Gotcha

fork-join and disable fork 페이지에서 fork와 더불어 join, join_any 그리고 join_none에 대해 알아보았다. 이번에는 그 중 forkjoin_none block에 대해 조금 더 자세히 알아보고자 한다. 우선 아래의 간단한 예제를 보고 출력을 예상해보자.

module top;
  
  int i;
  
  initial begin
    i = 0;    
    $display("i = %1d (before fork-join_none)", i);
    
    fork
      $display("i = %1d (inside fork-join_none)", i);
    join_none
    
    $display("i = %1d (after fork-join_none)", i);    
    i = 1;
  end
  
endmodule: top

initial block의 첫 번째 line에서 i의 값을 0으로 설정하였고 마지막 line에서 i의 값을 1로 설정하였기 때문에 얼핏 보면 그 사이에 위치하고 있는 $display statement의 출력은 모두 0일 것이라고 예상하기 쉽다. 하지만 실제로 출력되는 결과는 아래와 같다. forkjoin_none block 내에 위치한 $display statement의 출력 결과를 보면 i의 값이 1로 나타나는 점에 주목하자.

i = 0 (before fork-join_none)
i = 0 (after fork-join_none)
i = 1 (inside fork-join_none)

SystemVerilog LRM에서 그 이유를 확인할 수 있다. join_none에 대한 설명을 살펴보면 fork를 수행한 parent process에서 blocking statement를 수행하거나 parent process가 terminate 되기 전까지는 fork에 의해 생성된 child process가 실행되지 않음을 명시하고 있다. 위 예제에서는 i에 1의 값을 설정하는 blocking statement가 실행된 이후 forkjoin_none block 내에 위치한 statement가 수행된 것이다.

SystemVerilog join, join_any, join_none

생성된 child process가 즉시 실행되지 않고 위와 같은 조건을 만족한 이후에서야 실행되는 이유는 무엇일까? 이는 SystemVerilog 코드의 전반적인 process 실행 순서에 대한 control, 즉, process scheduling에 있어 일종의 determinism을 제공하고 race condition을 방지하기 위함이다.

forkjoin_none block 사용 시 많은 경우는 위와 같은 join_none 특성을 고려하지 않더라도 의도한 바와 같이 동작할 수 있겠지만, 경우에 따라 의도하지 않은 동작을 할 수도 있으므로 코드 작성 시 주의를 기울일 필요가 있다.

References

6 Comments

Post A Comment