线程之间的通信(事件event、信箱mailbox、旗语semaphore)

2024-03-27 01:10

本文主要是介绍线程之间的通信(事件event、信箱mailbox、旗语semaphore),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

看到一篇好博客,转载下https://blog.csdn.net/qq_41337361/article/details/122723681?spm=1001.2101.3001.6650.4&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-4-122723681-blog-113836405.pc_relevant_3mothn_strategy_and_data_recovery&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-4-122723681-blog-113836405.pc_relevant_3mothn_strategy_and_data_recovery&utm_relevant_index=8

目录

0.前言

1.事件event

2.信箱mailbox

3.旗语semaphore


0.前言

若多个线程之间想要进行数据交换或者知道彼此的状态以决定执行什么线程,SV中通过event、mailbox、semaphore来进行线程通信。其中event是2个线程之间的通信,semaphore是≥2个线程之间的通信。

1.事件event

当我们需要一个进程在另一个进程触发事件的时候运行该怎么办?SV中引入了event来解决这个问题。其语法如下:

触发:-> (非阻塞)(类比于接电话)

等待:@ or wait(阻塞)(类比于打电话)

注意:若用->和@搭配,一定要先@再->;若用->和wait搭配,则谁先谁后都可以。

为什么@和wait会有这种差别呢?因为@是等待边沿触发,而非1触发,因此必须先等,知道信号发生跳变,如果信号已经发生跳变了,@是察觉不到的;而wait是电平1触发,因此自然而然的弥补了@的缺点,因此也不用有先后顺序

->和@搭配:

  1. program automatic test();
  2. event e1,e2;
  3. initial begin
  4. $display("@%0d:1:before trigger",$time);
  5. ->e1;//->和@搭配,先->不行,非阻塞,去下一个
  6. @e2;//等待e2被触发,阻塞,下面的不执行
  7. $display("@%0d:1:after trigger",$time);
  8. end
  9. initial begin
  10. $display("@%0d:2:before trigger",$time);
  11. -> e2;//上面的等到了e2,此时上面的display运行
  12. @e1;//阻塞,顺序错误,下面的display不会执行
  13. $display("@%0d:2:after trigger",$time);
  14. end
  15. endprogram
  16. /* 仿真结果
  17. @0:1:before trigger
  18. @0:2:before trigger
  19. @0:1:after trigger */

->和wait搭配 :

  1. program automatic test();
  2. event e1,e2;
  3. initial begin
  4. $display("@%0d:1:before trigger",$time); //1
  5. -> e1;//触发1
  6. wait(e2.triggered);//阻塞,等待e2被触发
  7. $display("@%0d:1:after trigger",$time);//4
  8. end
  9. initial begin//顺序执行完后,再回到上面执行wait后的display
  10. $display("@%0d:2:before trigger",$time); //2
  11. -> e2;//e2被触发
  12. wait(e1.triggered);//e1已经被触发
  13. $display("@%0d:2:after trigger",$time);//3
  14. end
  15. endprogram
  16. /*仿真结果:
  17. @0:1:before trigger
  18. @0:2:before trigger
  19. @0:2:after trigger
  20. @0:1:after trigge */

wait_order:

wait_order阻塞等待多个事件的触发,并且要求这多个事件按照用户决定顺序触发。wait_order可以和else一同使用,当多个事件 按顺序触发时,执行wait_order后的语句,否则执行else后的语句。 

  1. module tb;
  2. event a, b, c;
  3. initial begin
  4. #10 -> a;
  5. #10 -> b;
  6. #10 -> c;
  7. end
  8. initial begin
  9. wait_order (a,b,c)
  10. $display ("Events were executed in the correct order");
  11. else
  12. $display ("Events were NOT executed in the correct order !");
  13. end
  14. endmodule

2.信箱mailbox

mailbox是一种在进程之间交换消息的机制。数据可以通过一个进程发送到Mailbox, 然后由另一个进程获取。数据可以是任何有效的SystemVerilog数据类型,包括类 class数据类型。

比如在一个验证环境中,generator将激励给driver,往往不是直接发送给driver,而是发送给generator和driver直接的mailbox,driver获取数据的时候,从mailbox中直接获得。

mailbox有几种SV自带函数,如下所示:

new()是对mailbox进行实例化;

put(xxx)是将数据放入mailbox中,是阻塞的,若mailbox放满,放不进去,则会一直重复放的动作,程序被阻塞到这个语句;

try_put(xxx)功能与put一样,但其是非阻塞的,放一次,放不进去就不放了;

get(xxx)是从mailbox中取数据,也是阻塞语句;

peek(xxx)和get()功能一致,但是get()从mailbox取出数据后,mailbox的数据就没了,而peek相当于复制了一份出来;num()是用来计算mailbox中有几个数据的。

关于mailbox的具体应用可参考这篇文章:SV小项目—异步fifo的简单验证环境搭建。

下面看代码进一步理解mailbox的运用:

  1. //============事务============
  2. class transaction;
  3. rand bit valid;
  4. rand bit [7:0] data;
  5. endclass
  6. //=================generator================
  7. class generator;
  8. mailbox #(transaction) gen2drv;//声明mailbox句柄,并且指明该mailbox中只能存放transaction类型的数据
  9. transaction tr;
  10. function new (input mailbox #(transaction) gen2drv);//声明和外界通信的组件时,一定要new
  11. this.gen2drv=gen2drv;
  12. endfunction
  13. task gen(input int num);//产生多少笔激励
  14. for(int i=0;i<num;i++) begin
  15. tr=new();
  16. assert(tr.randomize)
  17. gen2drv.put(tr);//把产生的一笔激励放入mailbox中
  18. $display(“trans valid =%d”,tr.valid);
  19. $display(“trans data =%d”,tr.data);
  20. #1ns;
  21. end
  22. endtask
  23. endclass
  24. //=====================驱动========================
  25. class driver;
  26. mailbox #(transaction) gen2drv;
  27. transaction tr;
  28. function new (input mailbox #(transaction) gen2drv);
  29. this.gen2drv=gen2drv;
  30. endfunction
  31. task run;
  32. tr=new();
  33. while(1) begin
  34. gen2drv.get(tr);//从mailbox中取出数据
  35. $display(“trans valid =%d”,tr.valid);
  36. $display(“trans data =%d”,tr.data);
  37. end
  38. endtask
  39. endclass
  40. //==================test文件==================
  41. program test;
  42. mailbox #(transaction) gen2drv;
  43. driver drv;
  44. generator gen;
  45. initial begin
  46. gen2drv=new();
  47. drv=new(gen2drv);
  48. gen=new(gen2drv);
  49. fork
  50. gen.gen(5);
  51. drv.run;
  52. join_any
  53. end
  54. endprogram

3.旗语semaphore

当多个线程访问同一资源的时候,而这个资源只允许一个线程访问的时候,就可以用旗语来进行控制;如果把资源比作为一个仓库的话,旗语就相当于一把钥匙,每个线程需要拿到钥匙后才能对资源进行访问。当然也可以有多把钥匙,对应同一资源可以同时被访问的最大数量。

旗语有如下几个操作函数:

new(); //对“钥匙”进行实例化

get(); //线程获取钥匙,阻塞

put(); //线程将钥匙放回,阻塞

try_get(); //非阻塞

  1. class bridge;
  2. semaphore key;//声明一个旗语钥匙
  3. function new ();
  4. this.key=new(1);//实例化1把钥匙
  5. endfunction
  6. task go_on(string name);
  7. $display(“@%0t: %s wants to go trough the brdige”,$time,name);
  8. key.get();//拿到钥匙
  9. #1ns;
  10. $display(“@%0t: %s gets permission to go trough the brdige”,$time,name);
  11. #10ns;
  12. endtask
  13. task go_off(string name);
  14. $display(“@%0t: %s goes off the brdige”,$time,name);
  15. key.put();//放回钥匙
  16. #1ns;
  17. $display(“@%0t: %s returned the key.”,$time,name);
  18. endtask
  19. endclass
  20. program test;
  21. bridge brg;
  22. string name1=”Alex”;
  23. string name2=”Bob”;
  24. string name3=”Calvin”;
  25. string name4=”Denise”;
  26. initial begin
  27. brg=new();
  28. fork
  29. begin
  30. brg.go_on(name1);
  31. brg.go_off(name1);
  32. end
  33. begin
  34. brg.go_on(name2);
  35. brg.go_off(name2);
  36. end
  37. begin
  38. brg.go_on(name3);
  39. brg.go_off(name3);
  40. end
  41. begin
  42. brg.go_on(name4);
  43. brg.go_off(name4);
  44. end
  45. join
  46. end
  47. endprogram

仿真结果如下:

可见若多个线程同时要拿钥匙,则按照先后顺序依次来;下一线程只有等到上一线程归还钥匙后才能拿到钥匙。 


http://www.taodudu.cc/news/show-8507319.html

相关文章:

  • vs2019新建Qt工程中双击 .ui 文件无法打开
  • createjs实现贪吃蛇,包含成长及游戏条件重置
  • 删除、创建、验证Kafka安装自带的__consumer_offsets topic
  • Java代码基础算法练习-报数问题-2024.03.26
  • Flutter 项目架构技术指南
  • LeetCode # 1372. 二叉树中的最长交错路径
  • linux ipc消息的权限,linux 下进程编程-System V IPC,消息队列,共享内存,旗语
  • systemverilog中线程间通信方法---事件event/旗语somaphore/信箱mailbox
  • SV-线程同步与通信-事件-旗语-信箱
  • Systemverilog线程之间的通信:事件【event】,旗语以及可执行代码
  • linux旗语
  • Semaphore旗语
  • Linux旗语编程实例
  • SystemVerilog进程间通信——旗语Semaphore/信箱Mailbox
  • 旗语(SEM)同步
  • SV中关于多线程同步的理解
  • 【2024美赛】F题(中英文):减少非法野生动物贸易Problem F: Reducing Illegal Wildlife Trade
  • 区块链如何改变世界贸易
  • 对外贸易经济大学计算机考研,对外经济贸易大学考研难吗?一般要什么水平才可以进入?...
  • 2022年自考专业考试(英语)国际贸易实务(一)练习题
  • 有一件事我想了很久了却一直没有做
  • 今天终于了却心头一块大事
  • pagehelper分页查询的一个坑,明明下一页没有数据了却还是返回了数据
  • js函数明明定义了却报未定义错误
  • kitti2bag包pip install pykitti明明安装了却显示没有
  • Maven导入依赖时爆红/导入依赖了却没用
  • ax2.set_xlim 不起作用,调整了却没有任何的作用
  • git远端分支建好了却无法获取远端分支
  • Pillow安装了却提示没有安装
  • el-form明明输入值了却一直报错
  • 链表面试题(动图详解)-明明做出来了却为什么没有Offer?
  • 全屏了却判断为未全屏(已解决)
  • 已经做烂了却还是不会做?
  • pagehelper分页查询明明下一页没有数据了却还是返回了数据
  • 踩雷之安装VMware Tools明明成功了却不生效
  • Tensorflow的gpu无法使用,明明安装了却用不了
  • 这篇关于线程之间的通信(事件event、信箱mailbox、旗语semaphore)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



    http://www.chinasem.cn/article/850466

    相关文章

    Spring Boot 中正确地在异步线程中使用 HttpServletRequest的方法

    《SpringBoot中正确地在异步线程中使用HttpServletRequest的方法》文章讨论了在SpringBoot中如何在异步线程中正确使用HttpServletRequest的问题,... 目录前言一、问题的来源:为什么异步线程中无法访问 HttpServletRequest?1. 请求上下文与线

    在 Spring Boot 中使用异步线程时的 HttpServletRequest 复用问题记录

    《在SpringBoot中使用异步线程时的HttpServletRequest复用问题记录》文章讨论了在SpringBoot中使用异步线程时,由于HttpServletRequest复用导致... 目录一、问题描述:异步线程操作导致请求复用时 Cookie 解析失败1. 场景背景2. 问题根源二、问题详细分

    Java对象和JSON字符串之间的转换方法(全网最清晰)

    《Java对象和JSON字符串之间的转换方法(全网最清晰)》:本文主要介绍如何在Java中使用Jackson库将对象转换为JSON字符串,并提供了一个简单的工具类示例,该工具类支持基本的转换功能,... 目录前言1. 引入 Jackson 依赖2. 创建 jsON 工具类3. 使用示例转换 Java 对象为

    Java多线程父线程向子线程传值问题及解决

    《Java多线程父线程向子线程传值问题及解决》文章总结了5种解决父子之间数据传递困扰的解决方案,包括ThreadLocal+TaskDecorator、UserUtils、CustomTaskDeco... 目录1 背景2 ThreadLocal+TaskDecorator3 RequestContextH

    java父子线程之间实现共享传递数据

    《java父子线程之间实现共享传递数据》本文介绍了Java中父子线程间共享传递数据的几种方法,包括ThreadLocal变量、并发集合和内存队列或消息队列,并提醒注意并发安全问题... 目录通过 ThreadLocal 变量共享数据通过并发集合共享数据通过内存队列或消息队列共享数据注意并发安全问题总结在 J

    Java文件与Base64之间的转化方式

    《Java文件与Base64之间的转化方式》这篇文章介绍了如何使用Java将文件(如图片、视频)转换为Base64编码,以及如何将Base64编码转换回文件,通过提供具体的工具类实现,作者希望帮助读者... 目录Java文件与Base64之间的转化1、文件转Base64工具类2、Base64转文件工具类3、

    异步线程traceId如何实现传递

    《异步线程traceId如何实现传递》文章介绍了如何在异步请求中传递traceId,通过重写ThreadPoolTaskExecutor的方法和实现TaskDecorator接口来增强线程池,确保异步... 目录前言重写ThreadPoolTaskExecutor中方法线程池增强总结前言在日常问题排查中,

    Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单

    《Springboot的ThreadPoolTaskScheduler线程池轻松搞定15分钟不操作自动取消订单》:本文主要介绍Springboot的ThreadPoolTaskScheduler线... 目录ThreadPoolTaskScheduler线程池实现15分钟不操作自动取消订单概要1,创建订单后

    C语言线程池的常见实现方式详解

    《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初

    Java子线程无法获取Attributes的解决方法(最新推荐)

    《Java子线程无法获取Attributes的解决方法(最新推荐)》在Java多线程编程中,子线程无法直接获取主线程设置的Attributes是一个常见问题,本文探讨了这一问题的原因,并提供了两种解决... 目录一、问题原因二、解决方案1. 直接传递数据2. 使用ThreadLocal(适用于线程独立数据)