07 Jul fork-join_none within a Loop (Multithreading)
이번 포스트에서는 for
, foreach
와 같은 loop 안에서 fork
–join_none
block을 사용하는 방법에 대해 소개하고자 한다. 물론 fork
–join
, fork
–join_any
block도 loop 안에서 사용할 수 있지만 가장 흔하게 사용되는 것이 바로 fork
–join_none
block을 이용한 multithreading이기 때문이다.
먼저 아래의 예제를 확인해보자. 두 개의 thread를 동시에 실행하기 위하여 fork
–join_none
block을 사용하고 있으며, index 값으로 0과 1을 각각 전달하고 있다. 아마 이 부분은 이해하는 데 어려움이 없을 것으로 생각된다.
module top; initial begin fork my_thread(0); my_thread(1); join_none end task my_thread(int idx); $display("thread #%1d", idx); // do something here... endtask: my_thread endmodule: top
하지만 동시에 수행해야 하는 thread의 개수가 매우 많을 때 위와 같은 방식으로 코드를 작성한다면 불필요하게 많은 line을 소모할 수 있다. 뿐만 아니라 thread의 개수가 dynamic하게 변경되는 상황에서는 위 방식을 사용할 수 없다. 이러한 점을 감안하여 코드를 아래와 같이 변경해보았다.
module top; int N; initial begin N = 3; // can be changed dynamically for (int i = 0; i < N; i++) begin fork my_thread(i); join_none end end task my_thread(int idx); $display("thread #%1d", idx); // do something here... endtask: my_thread endmodule: top
fork
–join_none
block과 for
loop를 이용하여 위에서 언급한 두 가지 문제를 모두 해결한 것처럼 보인다. 하지만 위 코드를 직접 실행해보면 그렇지 않다는 것을 알 수 있다. (순서는 simulator에 따라 다를 수 있지만) thread #0, thread #1, thread #2가 출력되어야 하나, thread #3만 세 번 출력되는 문제가 발생한다.
사실 이 문제의 원인은 fork-join_none Gotcha 페이지에서 이미 다룬 바 있다. fork
에 의해 생성된 child process는 매 iteration마다 바로 실행되는 것이 아니라 parent process가 blocking statement를 만났거나 terminate 되었을 때 실행된다. Child process가 실제로 실행되는 시점에는 for
loop가 이미 종료되었으므로 i
가 3의 값을 가지고, 그에 따라 thread #3만 세 번 출력되게 된다.
thread #3 thread #3 thread #3
그렇다면 어떻게 해야 원하는 결과를 얻을 수 있을까? 이에 대한 답은 SystemVerilog LRM에서 찾을 수 있다. automatic
변수를 이용한 방법이 제시되어 있는데, automatic
변수는 기본적으로 호출될 때마다 새로운 영역에 생성되어 initialize 되는 특성을 가지고 있다. 따라서 아래 코드에서는 매 iteration마다 0, 1, 2의 값을 가지는 local copy를 보관하게 되고, 이후 child process가 실행되는 시점에 각 local copy를 이용하게 되므로 의도하는 바와 같이 thread #0, thread #1, thread #2를 출력할 수 있는 것이다.
module top; int N; initial begin N = 3; // can be changed dynamically for (int i = 0; i < N; i++) begin fork automatic int j = i; // local copy, j, for each value of i my_thread(j); join_none end end task my_thread(int idx); $display("thread #%1d", idx); // do something here... endtask: my_thread endmodule: top
References
- https://ieeexplore.ieee.org/document/8299595
- https://iksciting.com/ieee-standard-for-systemverilog-1800-2017/
- https://blog.verificationgentleman.com/2014/03/a-subtle-gotcha-when-using-forkjoin.html
Jung Ik Moon
Verification Engineer
Marvin Petzold
Posted at 08:52h, 19 MarchI’d like to thank you for the efforts you’ve put in writing this website.
I am hoping to see the same high-grade content by you in the future
as well. In truth, your creative writing abilities has inspired me to get my very own site now 😉
abubakary depillo
Posted at 14:58h, 19 Marchabubakary depillo
anubis sawley
Posted at 14:28h, 22 Marchanubis sawley
Miley Clarke
Posted at 10:50h, 06 AprilMiley Clarke