概述
测试平台中的所有线程都需要同步并交换数据。(在测试平台中,不但设计层次的各个硬件模块实例在依靠信号做同步和数据交换,验证环境中的各个组件也需要做同步和数据交换。)
一个线程等待另外一个线程结束。验证环境中的同步和数据交换依靠的是软件方式
示例:
例如验证环境需要等待所有激励结束、比较结束才可以结束仿真。
比如监测器需要将监测到的数据发送至检查器,检查器又需要从不同的缓存获取数据进行比较。
线程同步类型1——事件(event)
可以通过event来声明一个event变量,并且去触发它。
声明一个event变量
//event来声明一个event变量
event event变量
// 这个event变量可以用来控制多个线程间的同步。
这个event变量,可以由一端去触发它,由另一端完成阻塞式的等待。所以可以用来控制多个线程间的同步。
触发事件的操作符:->
检查event触发状态:
- @操作符
- wait()
其它等待该事件的线程可以通过 @操作符和 wait()检查event触发状态,完成等待事件。
示例:
event done,blast; //声明两个独立的新事件done,blast
event done_too = done;//事件done赋值给done_too。注意:这两个变量都指向同一个事件
task trigger ( event ev ) ;//如果在调用该任务时时,传入了某个事件
-> ev; //就会通过->操作符触发这个事件
endtask
...
fork
@ done_too;//等待done_too
#1 trigger ( done ) ; //调用trigger任务, 触发done事件
//同时,在等待done_too事件的线程,会在trigger任务被调用之后
join //退出阻塞等待。因为触发的done事件,即会触发done_too事件。
fork
-> blast; //触发blast事件后
wait ( blast.triggered ) ;//利用wait()方法,完成电平触发等待
join //即去检查blast事件的状态是否已经被触发过
//只要被触发,或者已经被触发过wait()阻塞任务完成
多事件触发
当事件变量比较多时,可以利用多个事件前后触发的关系,来完成按照顺序的等待。
使用方法:wait_order()
使得线程保持等待,直到在参数列表中的事件event按照顺序从左到右依次完成。
如果参数列表中的事件被触发但是没有按照要求的顺序,那么会使得等待操作失败。
wait_order( a, b. c) ;
#参数列表中的事件被触发但是没有按照要求的顺序
wait_order( a. b, c ) else $display( "Error : events out oforder” ) ;
bit success;
wait_order( a. b, c ) success = 1; else success = 0;
线程同步类型2——旗语(semaphore)
旗语可以理解为打开共享资源大门的钥匙,因为多个线程有可能会对同一个资源进行访问,去修改或者读取数据。为了保护资源不被破坏,需要对共享资源做访问控制。常见保护方式:互斥访问保护。
举例:
线程A和线程B都有可能访问资源,旗语做的事是,确保线程A在访问资源的时候,线程B是无法访问的。只有线程A完成访问并且退出以后,线程B才可以访问资源。
看守共享资源的就是旗语,可以看作是打开共享资源大门的钥匙。
旗语的使用:
- 在创建旗语的时候,会为其分配固定的钥匙数量。(旗语在使用前要分配固定的钥匙数量)
- 使用旗语的进程必须先获得其钥匙,才可以继续执行访问资源。
- 旗语的钥匙数量可以有多个,等待旗语钥匙的线程也可以有多个。
- 旗语通常用于互斥,对共享资源的访问控制,以及基本的同步。
注意:声明旗语和例化旗语是两件事情。
创建旗语,并为其分配钥匙的方式如下:
semaphore sm;
sm = new() ;//如果不传递参数,钥匙的数量为0
创建一个具有固定钥匙数量的旗语:
new (N = 0)
从旗语那里获取一个或多个钥匙(阻塞型):
get (N = 1)
将一个或多个钥匙返回到旗语中:
put (N = 1)
尝试获取一个或多个钥匙而不会阻塞(非阻塞型):
try_get (N = 1)
旗语的内建方法:
semaphore是一个内建的类,它提供了下列方法
- new () 创建旗语
- put ()将钥匙数量返回给旗语(还钥匙)
- get ()从旗语中获取指定数量的钥匙。
- try_get()于从旗语中获取指定数量的钥匙,但不会被阻塞。
semaphore::new ()
创建旗语
new ()的原型如下:
function new (int keyCount = 0) ;
//keyCount 指定最初分配给旗语的钥匙数目。keyCount的默认值为0。
//当更多钥匙放入旗语时,钥匙数目可以超出初始时的keyCount数量,而不是删除。
//new ()函数返回旗语的句柄。
semaphore::put ()
将钥匙数量返回给旗语。
put ()的原型如下:
function void put (int keyCount = 1) ;
//keyCount指定返回到旗语的钥匙数量。默认值为1。
//调用semaphore.put ()函数时,指定数量的钥匙将返回到旗语。
//如果其它进程已经在等待旗语,则该进程应在有足够数量钥匙的情况下返回。
semaphore::get ()
从旗语中获取指定数量的钥匙。
get()的原型如下:
task get (int keyCount = 1) ;
//keyCount指定从旗语获取所需的钥匙数,默认值为1。
//如果指定数量的钥匙可用,则该方法返回并继续执行。
//如果指定数量的钥匙不足,进程将阻塞,直到钥匙数目充足。
旗语的等待队列是先进先出(FIFO),即先排队等待旗语的将优先得到钥匙。
semaphore::try_get()
从旗语中获取指定数量的钥匙,但不会被阻塞。
function int try_get (int keyCount = 1) ;
//keyCount指定从旗语处获取所需的钥匙数目,默认值为1。
//如果指定数量的钥匙可用,则该方法返回正数并继续执行。
//如果指定数量的钥匙不足,则该方法返回0。