SV 您所在的位置:网站首页 信箱多少才会满 SV

SV

2023-09-12 03:47| 来源: 网络整理| 查看: 265

3 mailbox 3.1概述

•    线程之间如果传递信息,可以使用mailbox。 •    mailbox和队列queue有相近之处。

•    mailbox是一个对象,因此也可以用new()来例化,例化时,有一个可选的参数size来限定其存储的最大数量,如果size是0或者没有指定,则信箱是无限大的,可以容纳任意多的条目。

•    使用put()可以把数据放入mailbox, 使用get()可以从信箱移除数据。 •    如果信箱为满,则put()会阻塞;如果信箱为空,则get()会阻塞。 •    peek()可以获取对信箱里数据的拷贝而不移除它。 •    线程之间的同步方法需要注意,哪些是阻塞方法,哪些是非阻塞 方法,即哪些是立即返回的,而哪些可能需要等待时间的。

3.2代码演练  program automatic bounded; mailbox mbx; initial begin mbx = new(l); //容量为1 fork // Producer线程 for (int i=l; i= 80 && tmp = 50 && spd = 30 && fuel = 80 && tmp = 50 && spd = 30 && fuel 0) ; val = q.pop_front(); $display ("car: : %s is %0d", name,val); //$display ("car: %s is %0d", name, val); end endtask endclass module road; car byd = new(); initial begin byd. drive(); end endmodule

通过队列改造来完成进程间通信的例子, 我们可以找出maibox与queue在使用时的差别:

maibox必须通过new()例化,而队列只需要声明。

mailbox可以将不同的数据类型同时存储,不过这么做是不建议的,对于队列来讲,它内部存储的元素类型必须一致。

mailbox 的存取方式put()和get()是阻塞方式,即使用它们时,方法不一定会立即返回,而队列所对应的存取方式,push_back()和pop_front()方法是非阻塞的,会立即返回。因此在使用queue取数时,需要额外填写wait(queue.size()>0)才可以在其后对非空的queue做取数操作,此外也应该注意,如果要调用阻塞方法,那么只可以在task中调用,因为阻塞方法是耗时的,而调用非阻塞方法,例如,queue中的push_back()和pop_front()方法,则既可以在task又可以在function中。

mailbox只能够用作FIFO,而queue除了按照FIFO使用,还有其它应用的方式例如LIFO(last in first out)

对于mailbox变量的操作,在传递形式参数时,实际传递并拷贝的是mailbox的指针,而在第二个例子中的task display(),关于queue的形式参数声明是ref方向,因为如果采用默认的input方向,那么传递过程中发生是数组的拷贝,以至于方向内部对queue的操作并不会影响外部的queue本身,因此在传递数组时,大家应该考虑到,对数组做的是引用还是拷贝,进而考虑端口的声明方向。

•    mailbox在例化时,通过new(N)的方式可以使其变为定长 (fixed length)容器。这样在负载到长度N以后,无法再对其写入。如果用new()的方式,则表示信箱容量不限大小。 •    除了put()/get()/peek()这样的阻塞方法,用户也可以考虑使用try _put()/try _get()/try _peek()等非阻塞方法。 •    如果要显式地限定mailbox中元素的类型,可以通过mailbox #(type = T)的方式来声明。例如上面的三个mailbox存储的是int, 则可以在声明时进一步限定其类型为mailbox #(int)。

3.4 event semaphore mailbox对同一功能的实现代码比较 

•    除了上面的三种常见需求, 有时候, 进程之间也需要同步。 这里我们来考虑, 如果要对这辆车熄火(stall)的话, 得先检查是否车挂挡在P (park) , 进而再将车钥匙拔出。 •    我们可以将stall和park两个线程的同步视作, 先由stall发起同步请求, 再等待park线程完成并响应同步请求, 最后由stall线程继续其余的程序, 最终结束熄火的过程。 •    我们不妨用之前掌握的SV三种进程通信的方式event、semaphore和mailbox来解决进程间的同步问题。

event代码实现: 

class car; event e_stall; event e_park; task stall; $display ( "car::stall started"); #lns; -> e_stall; @e_park; $display ( "car::stall finished") ; endtask task park; @e_stall; $display ("car: : park started"); #lns; -> e_park; $display("car::park finished"); endtask task drive() ; fork this.stall(); this.park(); join_none endtask endclass

semaphore 代码实现:

class car; semaphore key; function new(); key= new(0); endfunction task stall; $display("car::stall started"); #lns; key.put(); key.get(); $display("car::stall finished"); endtask task park; key.get() ; $display("car: :park started"); #lns; key.put() ; $display("car: :park finished"); endtask task drive(); fork this.stall(); this.park(); join_none endtask endclass

mailbox代码实现:

task stall; int val = 0; $display ("car:: stall started"); #lns; mb.put(val); mb.get(val); $display("car::stall finished"); endtask task park; int val = 0; mb.get(val); $display ("car::park started"); #lns; mb.put(val); $display("car::park finished"); endtask task drive(); fork this.stall(); this.park(); join_none endtask endclass

•    上面三种用来实现线程A请求同步线程B, 线程B再晌应线程A的同步 方式输出结果保持一致。 •    从这三段代码可以看出, 用来做线程同步的选择也有多种。

•    如果要在同步(事件)的同时, 完成一些数据传输, 那么更合适的是mailbox, 因为它可以用来存储一些数据,而event和semaphore更偏向于小信息量的同步, 即不包含更多的数据信息。 # car::stall started # car::park started  # car::park finished  # car::stall finished 

event: 最小信息量的触发,即单一的通知功能。可以用来做事件的触发, 也可以多个event组合起来用来做线程之间的同步。

semaphore: 共享资源的安全卫士。如果多线程间要对某一公共资源做访问,即可以使用这个要素。

mailbox: 精小的SV原生FIFO。在线程之间做数据通信或者内部数 据缓存时可以考虑使用此元素。

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有