news 2026/7/14 6:11:13

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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等同步机制。


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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 6:08:24

31-杨逢昌:制造业6S整改反弹根治体系——四级固化长效维持标准化方案,实现6S整改反弹率下降95%以上

「6S管理实战专题」第31篇 杨逢昌使命&#xff1a;用6S的力量&#xff0c;让10万名朋友实现高效愉悦的生活与工作。【制造业6S整改反弹根治体系】 ——《四级固化长效维持标准化方案》【开篇】在机械、钣金加工企业6S现场管理推进过程中&#xff0c;整改易、维持难、反弹快是行…

作者头像 李华
网站建设 2026/7/14 6:07:16

YOLO26魔改Bottleneck结构:多尺度特征融合与通道注意力机制

1. YOLO26魔改Bottleneck结构解析在目标检测领域&#xff0c;YOLO系列模型因其出色的实时性能一直备受关注。最近我们团队对YOLO26的Bottleneck结构进行了创新性改进&#xff0c;通过引入多尺度特征融合和通道注意力机制&#xff0c;在保持模型轻量化的同时显著提升了检测精度。…

作者头像 李华
网站建设 2026/7/14 6:03:54

C++多线程编程:深入解析std::unique_lock的RAII机制与高级应用

1. 项目概述&#xff1a;为什么需要std::unique_lock&#xff1f;在C多线程编程里&#xff0c;锁的管理是个既基础又容易出错的环节。很多朋友刚开始接触std::mutex时&#xff0c;习惯性地在临界区前后手动调用lock()和unlock()。这看起来直白&#xff0c;但一旦代码逻辑变复杂…

作者头像 李华
网站建设 2026/7/14 6:03:23

SPEGNet:伪装目标检测的协同感知架构与优化实践

1. 伪装目标检测的挑战与SPEGNet的突破在计算机视觉领域&#xff0c;伪装目标检测&#xff08;Camouflaged Object Detection, COD&#xff09;一直是个棘手的难题。想象一下在丛林环境中寻找一只与环境颜色完全融合的变色龙&#xff0c;或是雪地里几乎与背景无法区分的北极狐—…

作者头像 李华
网站建设 2026/7/14 6:02:25

VC++调用Core Audio API实现Windows默认音频设备一键切换

1. 项目概述与核心价值最近在做一个需要控制音频播放的小工具&#xff0c;发现一个挺实际的需求&#xff1a;如何让程序在启动时&#xff0c;或者根据用户的选择&#xff0c;自动切换到指定的扬声器或耳机上。Windows系统自带的音频切换虽然能用&#xff0c;但每次都要手动点开…

作者头像 李华
网站建设 2026/7/14 6:02:24

Java 程序员第 44 阶段20:大模型微服务拆分,独立服务解耦便于扩容维护,第44阶段项目实战总结:完整微服务拆分架构落地

[1. 阶段目标回顾与成果总览](#1-阶段目标回顾与成果总览)- [1.1 拆分前的系统现状](#11-拆分前的系统现状)- [1.2 阶段达成的核心目标](#12-阶段达成的核心目标)- [1.3 最终架构全景图](#13-最终架构全景图)[2. 各服务拆分实施总结](#2-各服务拆分实施总结)- [2.1 用户认证服务…

作者头像 李华