1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

for文で並列forkプロセスを複数個実行する

Last updated at Posted at 2020-06-14

SystemVerilogではfor文を使ってforkの並列プロセスを複数実行する事ができる。その際、forのindex変数をfork内に直接渡すのではなく、automaticで定義した変数に一旦渡す。

automatic変数を介する
module for_fork_test();
    initial begin
        int val[] = '{0,1,2,3,4,5};

        foreach(val[i])
            fork
                automatic int auto_i = i; // <====== This is necessary!!!!
                begin
                    #(10*auto_i);
                    $display("time %2t: process %0d finsihed, val = %0d", $time, auto_i, val[auto_i]);
                end
            join_none

        wait fork;

    end
endmodule
結果
 time  0: process 0 finished, val = 0
 time 10: process 1 finished, val = 1
 time 20: process 2 finished, val = 2
 time 30: process 3 finished, val = 3
 time 40: process 4 finished, val = 4
 time 50: process 5 finished, val = 5

automaticの変数を介さず直接渡すと。。。

直接渡す
module for_fork_test();
    initial begin
        int val[] = '{0,1,2,3,4,5,6};

        for(int i=0; i<6; i++)
            fork
                begin
                    #(10*i);
                    $display("time %2t, process %0d : val = %0d", $time, i, val[i]);
                end
            join_none

        wait fork;

    end
endmodule
結果
 time 60: process 6 finished, val = 6
 time 60: process 6 finished, val = 6
 time 60: process 6 finished, val = 6
 time 60: process 6 finished, val = 6
 time 60: process 6 finished, val = 6
 time 60: process 6 finished, val = 6

と、この様にforkの各プロセスの実行がfor文が回り終わってi=6となった後にスケジュールされる為、その時点でのi=6が参照されて、みんな同じ実行をしてしまう。

fork/join_noneでプロセス分岐した後、wait forkで全てのforkプロセスの終了を待つようにしているが、これは少し注意が必要。wait forkは同一のプロセス或いはそこからforkで分岐した子プロセス以下すべてのforkプロセスの終了を待つ。したがって、以下の様に他にforkがある場合にはそのプロセスの終了も待ってしまう。

他のforkプロセスも待ってしまう
module for_fork_test();
    initial begin
        int val[] = '{0,1,2,3,4,5};

        fork : first_fork
            forever #1000 $display("Hello!!");
        join_none

        //---------------------------------
        foreach(val[i])
            fork : second_fork
                automatic int auto_i = i;
                begin
                    #(10*auto_i);
                    $display("time %2t: process %0d finsihed, val = %0d", $time, auto_i, val[auto_i]);
                end
            join_none

        wait fork;  // <==== wait for both end of first_fork and second_fork!!!!
        //---------------------------------
    
    end
endmodule

この様にforeach文で分岐させたsecond_forkのラベルを付けたfork/join_noneプロセスの終了を待ちたいのに、first_forkのラベルを付けた別のfork/join_noneプロセスの終了も待ってしまう。この例の様にそのプロセスがずっと終わらないプロセスだとwait_forの先に進まない。
この様な場合どうすればよいかと言うと、wait forkとそれで待ちたいforkのみを別途ダミーのfork/joinで囲って、ひとまとまりのプロセスとして区別し、wait forkが効く範囲を限定する。wait forkが効く範囲は前述のとおり、同一プロセスとその子プロセス以下なので。

second_forkのみを待つ
module for_fork_test();
    initial begin
        int val[] = '{0,1,2,3,4,5};

        fork : first_fork
            forever #1000 $display("Hello!!");
        join_none

        fork : guard_fork
            begin //---------------------------------
            foreach(val[i])
                fork : second_fork
                    automatic int auto_i = i;
                    begin
                        #(10*auto_i);
                        $display("time %2t: process %0d finsihed, val = %0d", $time, auto_i, val[auto_i]);
                    end
                join_none

            wait fork;  // <==== wait for end of second_fork
            end   //---------------------------------
        join

    end
endmodule

以下参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?