当前位置: 首页 > news >正文

Systemverilog中fork...join等线程的使用

Systemverilog中fork...join等线程的使用

  • 前言
  • fork...join 三个变体的区别
  • fork...join 三个变体的典型应用场景
  • fork...join示例
  • fork...join_any示例
  • fork...join_none示例
  • 线程控制方法
    • wait fork
    • disable fork
  • 注意事项
    • 循环中的自动变量
    • join_none与#0延迟

前言

在 SystemVerilog​ 中,代码总是以initial块启动,从0时刻开始执行,并且顺序执行代码块。但在某些场景下,必须需要某些代码块并行执行,这时候就需要用到fork...join了。

fork...join及其变体是创建并发线程(并发进程)的核心机制,是测试平台(testbench)中实现多线程行为的核心结构之一,其是构建测试平台(Testbench)、实现并行激励和检查的关键。它允许在仿真中同时运行多个语句或任务,而不是像传统软件那样顺序执行。


fork…join 三个变体的区别


如上图所示,fork...join还存在fork...join_any、fork...join_none两个变体,这三者的区别在于何时解除对父线程的阻塞。具体区别如下:

进程类型行为描述类比
fork…join等待所有的子线程完成之后才可以继续执行后续代码整个部队全队集合完毕才可以出发
fork…join_any任意一个子线程完成之后,就可以继续执行后续代码,其余未完成的线程会继续执行只要有一个人都到达终点,教练就继续下一个项目
fork…join_none立刻执行后续的代码,不等待任何子线程,所有子线程在后台并发执行发令枪响,运动员开跑,裁判立刻去忙别的事

fork…join 三个变体的典型应用场景

  • fork…join的典型应用场景
    • 并行测试:同时驱动多个接口,且等待全部发送完成后检查结果;例如在验证环境中同时发送多笔事务,所有事务处理完成后再统一进行对比;
    • 多通道数据采集:从多个接口信号采集数据,要确保所有接口均采集完成后再进行下一步处理;
  • fork…join_any的典型应用场景:
    • 超时保护:当前执行的任务和延迟计数器并行运行,当前任务和延迟计数器哪个先完成就退出等待;
    • 竞争仲裁:若多个模块同时请求资源,哪个模块先完成就先获取到资源;
  • fork…join_none的典型应用场景
    • 看门狗:启动一个信号状态监视的进程,该进程用于看门狗,不影响主进程的运行;
    • 动态线程池:可在循环中不断启动子线程,而主线程可以立刻执行其他操作,无需等待每个子线程结束;

fork…join示例

initial begin $display("@%0t UVM_Frequency: fork...join Start",$time);fork #10$display("@%0t UVM_Frequency: process A",$time);#5$display("@%0t UVM_Frequency: process B",$time);#15$display("@%0t UVM_Frequency: process C",$time);join $display("@%0t UVM_Frequency: fork...join end",$time);end

在上述示例中,最终的打印信息为:

@0UVM_Frequency:fork...join Start @5ns UVM_Frequency:process B @10ns UVM_Frequency:process A @15ns UVM_Frequency:process C @15ns UVM_Frequency:fork...join end

在UVM环境中的运行结果如下:


fork…join_any示例

initial begin $display("@%0t UVM_Frequency: fork...join_any Start",$time);fork #10$display("@%0t UVM_Frequency: process A",$time);#5$display("@%0t UVM_Frequency: process B",$time);#15$display("@%0t UVM_Frequency: process C",$time);join_any $display("@%0t UVM_Frequency: fork...join_any end",$time);end

在上述示例中,最终的打印信息为:

@0ns UVM_Frequency:fork...join_any Start @5ns UVM_Frequency:process B @5ns UVM_Frequency:fork...join_any end @10ns UVM_Frequency:process A @15ns UVM_Frequency:process C

在UVM环境中的运行结果如下:


fork…join_none示例

initial begin $display("@%0t UVM_Frequency: fork...join_none Start",$time);fork #10$display("@%0t UVM_Frequency: process A",$time);#5$display("@%0t UVM_Frequency: process B",$time);#15$display("@%0t UVM_Frequency: process C",$time);join_none $display("@%0t UVM_Frequency: fork...join_none end",$time);end

在上述示例中,最终的打印信息为:

@0ns UVM_Frequency:fork...join_none Start @0ns UVM_Frequency:fork...join_none end @5ns UVM_Frequency:process B @10ns UVM_Frequency:process A @15ns UVM_Frequency:process C

在UVM环境中的运行结果如下:


线程控制方法

为了管理好fork...join的并发线程,systemverilog提供了两个重要的控制语句:wait forkdisable fork


wait fork

该语句用于等待当前进程中的所有子进程全部结束后才会结束仿真,包括fork...join_none产生的进程,具体如下:

  • 等待所有子进程结束wait fork会等待当前进程直接或间接创建的所有子进程都终止(包括执行完成或者被disable fork强行终止);
  • 灵活的同步点:与fork...join必须在同一个fork中等待所有子进程结束不一样,wait fork可以在后续任意时刻执行,其允许先启动一部分进程,执行一些其他操作,最后统一等待他们完成;即wait fork可跨多个fork块,等待调用者所有活跃的子进程结束;
  • 避免进程泄漏:若不使用wait fork,则有可能在父进程执行结束之后,尚未完成的子进程仍在后台运行,有可能会导致信号意外被驱动或者资源占用;
  • 注意事项
    • 只能作用于initialalwaystaskfunction等过程块;
    • 不关心其他进程,只关心当前进程的后代;
    • 若当前进程没有子进程,则wait fork会立即返回,不阻塞执行其他进程;
  • wait fork代码示例
initial begin $display("[%0t]UVM_Frequency: paraent process start",$time);fork begin #10;$display("[%0t]UVM_Frequency: son process A end",$time);end begin #20;$display("[%0t]UVM_Frequency: son process B end",$time);end join_none// 父进程不阻塞$display("[%0t]UVM_Frequency: paraent process continue",$time);#5;$display("[%0t]UVM_Frequency: paraent process wait son process",$time);wait fork;// 等待所有子进程结束$display("[%0t]UVM_Frequency: all son process end,paraent process continue",$time);#10$finish;end

上述代码的运行结果为:

[0]UVM_Frequency:paraent process start[0]UVM_Frequency:paraent processcontinue[5]UVM_Frequency:paraent process wait son process[10]UVM_Frequency:son process A end[20]UVM_Frequency:son process B end[20]UVM_Frequency:all son process end,paraent processcontinue

在UVM环境中的运行结果如下:


disable fork

该语句用于终止当前进程中的所有子进程,强行停止这些进程。常用于超时控制、异常退出等,具体如下:

  • 终止所有由当前进程派生的子进程disable fork会终止包含fork直接创建的进程及子进程内部再次fork产生的后代进程,并将其递归终止;
  • 释放资源disable fork可以停止一些不需要的后台监控、超时计数器等,避免其产生意外的副作用;
  • 与wait…fork一起配合完成精准控制:可以先用disable fork终止一些不需要的进程,再用wait fork等待剩余进程自然结束,确保完成同步;
  • 注意事项
    • 只能作用于initialalwaystaskfunction等过程块;
    • 其作用于调用它的那个进程所拥有的子进程,而不会影响兄弟进程或父进程的其他分支;
    • 谨慎使用disable fork,若滥用disable fork则会有概率导致难以调试的竞态条件,其会突然终止正在运行的进程,从而导致某些信号处于不确定状态;
  • disable fork代码示例
initial begin fork begin:outer $display("[%0t]UVM_Frequency: outer start",$time);fork begin:innerA #20;$display("[%0t]UVM_Frequency: inner A end",$time);end begin:innerB #40;$display("[%0t]UVM_Frequency: inner B end",$time);end join_none #10;$display("[%0t]UVM_Frequency: outer end",$time);end join_none #5;$display("[%0t]UVM_Frequency: paraent process continue executing disable_fork",$time);disable fork;// 终止外层及其所有内层子进程#10$finish;end

上述代码的运行结果为:

[0]UVM_Frequency:outer start[5]UVM_Frequency:paraent processcontinueexecuting disable_fork

在UVM环境中的运行结果如下:

即在5ns的时候disable fork终止了外层进程outer,进而递归终止了其内部的内层进程innerAinnerB,因此innerAinnerBouter的结束打印信息均不会出现。


注意事项

循环中的自动变量

fork循环中,如果使用静态变量(如下面示例中的i),那么产生的所有线程将会共享该变量,从而会导致结果有误,错误示例如下:

for(inti=0;i<10;i++)begin fork $display("UVM_Frequency: i = %0d",i);// 危险!所有线程看到的i都是最终值10join_none end

上述代码在UVM环境中的运行结果如下,所有线程看到的i都是最终值10。

正确做法是使用automatic,具体如下:

for(inti=0;i<10;i++)begin automaticintj=i;fork $display("UVM_Frequency: j = %0d",j);join_none end

上述代码在UVM环境中的运行结果如下:


join_none与#0延迟

当采用fork...join_none时,其启动的线程虽然立刻开始调度,但是在#0内(即零延时),父线程的后续代码会优先执行。
若需要子线程先执行的话,可以采用mailbox等同步机制。


💓 💖 💓 ~ 本节完结 ~ 💓 💖 💓

http://www.jsqmd.com/news/1185383/

相关文章:

  • 云原生安全爆火!2026企业攻防主战场:容器、K8s成漏洞重灾区
  • 格拉苏蒂官方更换原装表带价格查询|热线电话与门店地址权威信息公告(2026年7月最新) - 亨得利钟表维修中心
  • 亲身到店探访北京泰格豪雅官方售后服务中心|最新地址与24小时售后热线(2026年7月最新) - 亨得利官方服务中心
  • 俄罗斯酒类营销合规指南:法律红线、文化禁忌与精准触点设计
  • spdlog跨C++标准版本兼容性实战:从C++11到C++20的日志库适配方案
  • openeuler/yocto-meta-arm核心功能解析:为什么它是Arm嵌入式项目的必备工具
  • SecGPT-Agent:为AI智能体构建原生安全隔离架构的实战指南
  • 在 PMP(项目管理专业人士)考试中第一章到第三章的引论与项目运行环境构成了整个 PMBOK 体系的基石
  • 工业负载控制方案:TPD2017FN与PIC18F46K20的协同设计
  • JavaScript数组遍历7种方式深度对比与工程选型指南
  • C++图形编程入门:从控制台字符到图形库绘制对角线的完整指南
  • 2026实力之选:水泥板/纤维水泥板/防火水泥板品牌的前沿格局与长期价值 - 甄选服务推荐
  • 2026年 常州打包搬运公司推荐榜:专业拆装与精密搬运团队的优质之选 - 甄选服务推荐
  • C++环形缓冲区实现:高性能数据流处理的核心数据结构
  • 推荐江苏三相UPS不间断电源厂家 - 品牌推广大师
  • 亲身到店探访郑州亨得利官方名表服务中心|完整网点地址与服务电话(2026年7月更新) - 亨得利官方博客
  • 4K视频修复技术解析:从超分辨率到AI增强的完整指南
  • 实战篇:小样本预测利器——灰色预测模型全流程解析
  • 直流电机静音控制:TB9051FTG与PIC18F86J16的优化方案
  • 盐城盐都区张庄街道亨得利官方钟表服务中心电话公示(2026年7月最新) - 亨得利官方博客
  • OpenClaw:私有化部署的AI助手系统架构与应用
  • 经典CNN网络演进:从LeNet到ResNet的核心突破与实战应用
  • C++父子进程通信:从匿名管道到本地套接字的实战指南
  • C++输入输出流深度解析:从cin/cout到健壮I/O编程实践
  • 一文读懂底层逻辑,什么是GEO?为什么2026年企业必须做GEO
  • 亨得利官方钟表服务中心|全部网点地址与热线权威信息声明(2026年7月更新) - 亨得利官方
  • 浙大AI绘画加速方案:即插即用实现5倍Stable Diffusion推理优化
  • 2026年 方形纸筒厂家推荐排行榜:坚固环保、高定包装与仓储纸筒源头企业精选! - 甄选服务推荐
  • 2026华为OD面试题022:分辨率排序
  • 计算机毕业设计之基于jsp旅游信息管理平台