前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >for循环+fork-join_none结构的坑,你有注意到吗?

for循环+fork-join_none结构的坑,你有注意到吗?

作者头像
IC验证
发布2020-06-30 11:43:05
1.3K0
发布2020-06-30 11:43:05
举报
文章被收录于专栏:杰瑞IC验证杰瑞IC验证

来源| 杰瑞IC验证(ID:Jerry_IC)

|原创作者| Jerry

1. 回忆下fork-join_none

fork-join_none相信大家应该熟悉了,新来的朋友可以回顾下jerry之前的文章,就是之前jerry提到的那个“暴脾气”的哥们,他不会去等别人,直接会着急做自己的事情。

前文回顾(点击查看):fork-join挺好用的了,fork-join_any、fork-join_none有什么用?

回顾下那篇文章中我们举的一个例子,这个暴脾气可以这么用:

代码语言:javascript
复制
fork

     aa( );       

     aa( );

     aa( );

    ……

     aa( );

     aa( );

join

如上代码,我们想要并行的执行100个 aa( )这个函数进程。通过fork-join要写到手软,用这个暴脾气,几句话就搞定:

代码语言:javascript
复制
for(int i=0; i<100; i++)

fork

     aa( );       

join_none

但是,今天jerry告诉各位初学者,这个暴脾气有不好驾驭的那一面的哦,弄不好就很容易翻车!!

2. fork-join_none翻车现场

什么情况下容易翻车呢?

大家仔细看看上面的例子,并行运行的aa( ),都是一样的内容,放在for循环中,却并没有使用for循环的循环因子 i 啊~

有人说,这有什么关系吗?

好的,来,看看jerry今天准备的代码,逼出它的邪恶面!

我们还是通过暴脾气fork-join_none,外加for循环,这次我们用上for的循环因子i,

怎么用i呢?我们直接通过$display来打印,打出10个选美者的编号和颜值等级:

代码语言:javascript
复制
for (int i=0 ; i<10; i++)

fork

       $display(“No%0d,My face_grade is %0d”, i ,i );

join_none

大家先不看答案,先猜猜,这个会怎么打?

算了,jerry先猜猜你们是怎么想的?是不是打印出下面这样?

No0,My face_grade is 0

No1,My face_grade is 1

No2,My face_grade is 2

No3,My face_grade is 3

……

No9,My face_grade is 9

大错特错!!太天真了!这个时候这个暴脾气只会在电脑的某个角落里看着你笑着说“愚蠢的人类”!!

jerry告诉你打印出来的是什么:

No10,My face_grade is 10

No10,My face_grade is 10

No10,My face_grade is 10

……

No10,My face_grade is 10

太阴险了!怎么会是这样呢?我0-9怎么还出来10了?

3. 再认识下for循环

先解释下这个for循环范围0-9,怎么打出来10了?

看下这段代码:

代码语言:javascript
复制
int apple_num;

for (apple_num=0 ; apple_num<10; apple_num++);

       $display(“i have %0d apples”, apple_num );

直接告诉大家,这个代码打印出来的是:

i have 10 apples

这个代码,for循环是执行的一个空语句,for结束后才进行打印循环因子。让不注重细节的伙伴们再认识下for,for在最后执行完成他的值是还要再走apple_num++的,正是因为加到了10,才不满足apple_num<10的条件不再进行循环下去了。

我们再回头看看这个代码:

代码语言:javascript
复制
for (int i=0 ; i<10; i++)

fork

       $display(“No%0d,My face_grade is %0d”, i ,i );

join_none

现在知道这个打印出来10是怎么来的了,是for循环执行完了以后循环因子i的值啊!!

好像差不多理解了:for循环的时候依次创建了10个进程,然后等for循环结束后,才并行执行10个fork进程。

因为fork-join_none,for全部循环完了以后, 10个$display(“No%0d,My face_grade is %0d”, i ,i ); 才并行的执行完!!在打印的时候得到的i值就是最后的10了。换句话理解:这10个并行的$display里面的i其实是同一个int i,i++是会改变它的。

4. 怎么防止它的翻车

来,jerry先直接告诉各位怎么解这个问题:

代码语言:javascript
复制
for (int i=0 ; i<10; i++)

fork

      automatic int j=i;

       $display(“No%0d,My face_grade is %0d”, j ,j );

join_none

f

这段代码打印的正是我们期望的:

No0,My face_grade is 0

No1,My face_grade is 1

No2,My face_grade is 2

No3,My face_grade is 3

……

No9,My face_grade is 9

为什么呢?我们来分析一下:

如上代码,我们加了一个automatic int j=i 转了一下,把i给j,我们打印j。

此处automatic类型,意味着进入fork进程被创建,结束被撤销。保证了10个并行的display语句,每个进程中的j是它自己的,是独一无二的(不清楚automatic和static的区别的可以自己查或者关注jerry后面的文章哈)。

先不要恍然大悟,仔细想想,仅仅保证了独一无二,就行了?automatic int j=i;

这句话还没执行,for不就应该执行完了?那这里的i岂不是还是应该是10??

是啊!除非……?

没错!

automatic int j=i;在i++之前就执行了!!!

我们来验证下,假如这么写:

代码语言:javascript
复制
for (int i=0 ; i<10; i++)

fork

      #0;

      begin

       automatic int j=i;

       $display(“No%0d,My face_grade is %0d”, j ,j );

      end

join_none

果然就又出错打印成下面这样了!!!

No10,My face_grade is 10

No10,My face_grade is 10

No10,My face_grade is 10

……

No10,My face_grade is 10

其实不要说那样,就即便如下这样都是不对的!!

代码语言:javascript
复制
for (int i=0 ; i<10; i++)

fork

      automatic int j;

        j=i;

       $display(“No%0d,My face_grade is %0d”, j ,j );

join_none

看来除了保证独一无二,更关键的原因是执行顺序!!

什么执行顺序呢?

简单的说,如果把我们这段代码理解为两个过程:“创建进程”、“执行进程”。

创建进程的时候,创建10个并行的进程,然后统一执行。

这句神奇的automatic int j=i;偏偏就是在创建进程的过程中就执行了!

大家可以看一下下面的视频,DVE上的断点单步调试,上面提到的两种代码执行顺序对比:

先执行的94行for进入第一段代码“创建线程”阶段,然后马上95行神奇的automatic int j=i;可见它也是第一段代码“创建线程”阶段执行的!然后并没有接着执行96行的display,而是101行的for!进入了第二段代码的“创建线程”阶段!线程都创建完成之后才再回去96行进入执行进程阶段,执行了display,最后执行了102行的display。

各位初学者可以这样简单的理解这段代码,但是其实呢要更进一步探究就涉及到了

sv的仿真调度机制!!!

先简单看一眼,就是这些个东西啦:

我擦,短短几句代码需要想到这么多知识吗?这里这个调度机制我们就先不深究了,大家先擦擦汗,jerry后面的文章会娓娓道来的~

我们回到今天要讲的重点:“for循环+fork-join_none结构”的坑,怎么处理呢?最简单的一种方式就是用一个automatic int j=i 转一下,一定要在fork的一开始定义,并且赋值。

今天这个知识点很常见,很重要哦,希望各位初学者不要着急,像这样的知识点,jerry聊一个就记住一个就好,不怕慢只怕站~哈哈,继续关注jerry后面的文章,一起成长~加油!

——The End——

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-03-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 杰瑞IC验证 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档