首页 > 编程知识 正文

并发与线程的关系

时间:2023-05-06 03:44:45 阅读:246855 作者:2866

文章目录 一、mgdmy、fork..join类型2.1 fork..join2.2 fork...join_any来同步线程2.3 fork...join_none来产生线程 三、线程通信3.1event事件3.2mailbox3.3 semaphore旗语

一、简介

要了解什么是线程之前,我们要了解什么叫进程。进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。线程是指进程中的一个执行流程,一个进程中可以运行多个线程。

在实际硬件中,时序逻辑通过触发器和时钟来激活,组合逻辑通过输入变化而变化。在Verilog中也是通过initial和always、连续赋值语句等进行模拟。但是对于我们的验证环境来说,我们会使用许多并发执行的线程,这要求sv能够控制和不断选择下一个要运行的线程。

二、fork…join类型

2.1 fork…join

必须等内部所有语句执行完成才能继续块内后续的线程。

module test();initial begin $display("%t : AAAA",$time); #10 $display("%t : BBBB",$time); fork $display("%t : CCCC",%time); #50 $display("%t :DDDD",$time); #10 $display("%t :EEEE",$time); begin #30 $display("%t :FFFF",$time); #10 $display("%t :GGGG",$time); end join $display("%t:HHHH",$time); #80 $display("%t :IIII",$time); endendmodule


代码说明:

fork…join里面的begin…end是顺序执行的,所以#40 F、#50 G ;D 是#10 B+#50所以是60;I是#140是因为里面fork…join里面最长的是#60,所以I是140; 2.2 fork…join_any来同步线程

对块内语句进行调度,当第一个语句完成后,父线继续执行

module test();initial begin $display("%t : AAAA",$time); #10 $display("%t : BBBB",$time); fork $display("%t : CCCC",%time); #50 $display("%t :DDDD",$time); #10 $display("%t :EEEE",$time); begin #30 $display("%t :FFFF",$time); #10 $display("%t :GGGG",$time); end join_any $display("%t:HHHH",$time); #80 $display("%t :IIII",$time); endendmodule


注意:

之类fork…join_any,只要语句中有任何一个语句执行完后,父语句就可以执行,这里看到在C执行完后H执行了。fork…join_any一般用来同步线程,也就是如果想要某几个线程并行执行,而不影响其他的线程的执行,这里使用了fork…join_any后就可以同步语块中的线程。 2.3 fork…join_none来产生线程

在调度其块内语句时,父线继续执行

module test();initial begin $display("%t : AAAA",$time); #10 $display("%t : BBBB",$time); fork $display("%t : CCCC",%time); #50 $display("%t :DDDD",$time); #10 $display("%t :EEEE",$time); begin #30 $display("%t :FFFF",$time); #10 $display("%t :GGGG",$time); end join_none $display("%t:HHHH",$time); #80 $display("%t :IIII",$time); endendmodule

注意:线程H先于fork里面的语句执行

fork_join_none的意思是不需要fork_join_none语句中的语句执行完,父语句就可以接着继续执行,这里的H在C之前执行。fork…join_none一般用来添加线程。 三、线程通信 对于硬件来说模块内部各个过程语句可以看成是多个在0时刻一起并行执行的线程。如果这些并行的线程之间进行通信或者是同步,例如饮料机中的取消信号进来,不同的always语块要相互通知。这里是用过信号的变化完成的。对于软件,也就是验证环境来看,多个线程(就是多个task)是even、旗语、mailbox等进行通信和同步。 3.1event事件 event是静态的同步对象句柄,翻译翻译就是句柄一般可以是不同对象,是一个动态的,这里的even是一个静态的,只是指明一个事件;可以用于线程同步,可以被赋值给其他事件,这样两个事件句柄会指向同一个对象,触发任意一个句柄就触发这个事件;可以传递给队列、function和task;触发:->even_handle,等待:@ or wait(even_handle.triggered)

@和wait的qu区别
解释

如果在timeslot中,触发发生在@前则@是无法探测到,这就要求@一直需要提前挂着等待,如果没有捕捉到就会一直阻塞;在trigger的情况中,整个timeslot都可以探测到,trigger属性是一种能够查询事件是否已经被触发,而不是只检查当前时刻,线程只等待结果,不是在@出阻塞; program automatic test();event e1,e2;initial begin $display("@%0d : 1 :before trigger",$time); ->e1; wait(e2.triggered); $display("@%0d : 1 :before trigger",$time);endinitial begin $display("@%0d : 2 :before trigger",$time); ->e2; wait(e1.triggered); $display("@%0d : 2 :before trigger",$time); endendprogram

定义了两个事件,首先两个initial块都并行执行,然后在0时刻先打印“befor trigger”;并且加入调换两个initial块的顺序,它们的before trigger也会更换。然后同时触发了e1和e2,wait的模式是两个都能够被触发到。 program automatic test();event e1,e2;initial begin $display("@%0d : 1 :before trigger",$time); ->e1; @e2; $display("@%0d : 1 :before trigger",$time);endinitial begin $display("@%0d : 2 :before trigger",$time); ->e2; @e1; $display("@%0d : 2 :before trigger",$time); endendprogram 这里只会打印@0:1:afer trigger,这是因为在两个initial语块中虽然并行,但是在仿真器中也是有顺序的,它挂起只检测到e2的触发。
写的挺好的IPC 3.2mailbox

可以这么理解:virtual interface 是TB和dut之间连接,然后mailbox是类之间的连接。官方的说法是mailbox是进程之间交换消息的机制,数据可以通过一个进程发送到mailbox,然后由另一个进程获取。其中数据可以是任何有效的systemVerilog数据类型。

Methoddescriptionnew()creat a mailboxput()place a message in a mailboxtry_put()try to place a message in a mailbox without blockingget()/peek()retrieve a message from a mailboxnum()returns the number of messages in the mailboxtry_get()/try_peek()try to retrieve a message from a mailbox without blocking

mailbox分类

有界邮箱(bounded mailbox):邮箱的大小是指定的,如果邮箱满了,那么对邮箱的写入操作就会被挂起,直到邮箱再次有空间;无界邮箱:没有大小限制;
根据存放数据类型划分:通用型:可以放任何数据类型,mailbox mailbox_name;;参数型:可以存放指定数据类型mailbox#(type) mailbox_name;; class transcation;rand bit valid;rand bit [7:0]data;endclassclass generator;mailbox #(transcation) gen2drv;transcation tr;function new(input mailbox #(transcation)gen2drv); this.gen2drv = gen2drv;endfunctiontask gen(input int num); for(int i = 1;i < num;i++)begin tr = new(); assert(tr.randomize) gen2drv.put(tr); $display("trans valid = %d",tr.valid); $display("trans data = %d",tr.data); #1ns; endendtaskendclassclass driver;mailbox #(transcation)gen2drv;transcation tr;function new(input mailbox #(transcation) gen2drv); this.gen2drv = gen2drv;endfunctiontask run;tr = new();while(1)begin gen2drv.get(tr); $display("trans valid = %d",tr.valid); $display("trans data = %d",tr.data);endendtaskendclassprogram test;mailbox #(transcation) gen2drv;driver drv;generator gen;initial begin gen2drv = new(); drv = new(gen2drv); gen = new(gen2drv); fork gen.gen(5); drv.run; join_any end endprogram

di

generator是不断的产生新的tr然后放到mailbox里面,然后driver去取mailbox的值。在top_tb里面是先定义不同类的句柄,然后传递mailbox进去,之后在每个类构造中都放进去mailbox。最后在进行task。 3.3 semaphore旗语

设想一下,家里只有一台车,然后车也只有一把钥匙。如果家里人都会开车,那么假如爸爸出门要上班开车,并且把这把钥匙取走后,妈妈假如出门买菜,只能等爸爸把车钥匙换回来才能出门买菜。semaphore也是,semaphore主要用于对共享资源进行管理,通常共享资源在不同的进程中使互斥使用的,在内存中创建semaphore时,类似于创建了一个篮子(bucket),篮子中包含了一定数量的钥匙(keys),要获取共享的资源,必须从篮子中获取一把或多把钥匙,在获取完资源后必须将钥匙放回到篮子中;如果此时另一个线程试图获取篮子中的资源,必须等到桶中有足够多的钥匙的时候才能进行,否则会一直阻塞在这里.。

Methoddescriptionnew()creat a semaphore with a specified number of keysget()obtain one or more keys from the bucketput()obtain one or more keys from the buckettry_get()try to obtain one or more keys without blockingclass bridge;semaphore key;function new(); this.key = new(1);endfunctiontask go_on(string name); $display("@%0t : %s wants to go trough the bridge",$time,name); key.get(); #1ns; $display("@%0t : %s gets permission to go trough the bridge",$time,name); #10ns;endtasktask go_off(string name); $display("@%0t : %s wants to go off the bridge",$time,name); key.put(); #1ns; $display("@%0t : %s return the key",$time,name);endtaskendclassmodule top_tb;bridge brg;string name1 = "xhdnp";string name2 = "Bob";string name3 = "Calvin";string name4 = "kldwl";initial beginbrg = new();fork begin brg.go_on(name1); brg.go_off(name1);end begin brg.go_on(name2); brg.go_off(name2);end begin brg.go_on(name3); brg.go_off(name3);end begin brg.go_on(name4); brg.go_off(name4);endjoinendendmodule

Java聊天室之实现获取Socket功能JS中switch的四种写法示例无论如何如何重新分配内存RocketMQ 消息失败重试 解析——图解vue脚手架vue-cli的卸载与安装方式SSM框架的优缺点是什么

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。