这篇文章主要讲下SV中的线程。软件环境中的initial块对语句主要有两种分组方式,使用begin...end或者fork..jion,其中begin...end是以顺序方式执行,fork ...jion是以并发的形式执行。
这里讲下fork三兄弟的区别:1.fork...jion在begin end块里面并发执行,知道所有的线程都执行完毕了,再进行下一个阶段。
2.fork join any 在begin end块里面并行执行,知道有一个执行完毕,就可以进入下一个阶段。
3.fork join none 在beginend块里面并行执行,无需等待直接进入下一个阶段。
当然,如果我们想等待fork块里面所有的线程都执行完毕再退出,我们可以使用wait fork。如果我们咋i使用了fork jion any或者fork join none之后,可以使用disable来指定需要停止的线程。停止多个线程可以使用disable fork。
接下来讲一讲线程的通信,线程之间的通信指的是所有线程都需要同步并交换数据。再verilog中,一个线程总要等待一个带着@操作符的事件,此操作符是边沿敏感的,所以总是阻塞着等待着事件的变化,其他的线程可以通过->来储发事件,结束对第一个线程的阻塞。当然,我们也可以使用电平敏感的wait(e1.triggered())来代替边沿敏感阻塞语句,此方法对比@来说,只要event被储发过,就可以放置引起阻塞。
接下来讲一讲旗语,旗语主要有三个操作:1.new()方法可以创建一个带有一个或者多把钥匙的旗语。2。使用get()可以获得一把或者多把钥匙。3.使用put()可以返回一个或者多把钥匙。
当然,加入你试图获取一个旗语但不希望被堵塞,可以使用try_get()函数,他返回1表示有足够的钥匙,返回0表示钥匙不够。
接下来讲一讲信箱。再线程之间传递消息也可以使用信箱,信箱同样需要new()来例化,使用get()从信箱中一处数据,是由put()把数据放进信箱。如果信箱满了,put()函数会阻塞;如果信箱空了使用get()会阻塞,使用peek可以获取信箱中的数据拷贝而不将他移除。这里一定要注意,put()和get()都是阻塞方法。
最后。让我们来看看event,旗语,信箱的优劣:
event具有的是单一的通知功能,可以用来做事件的储发,也可以多个event组合起来用作线程之间的同步,
旗语:如果多线程间要对某一公共资源做访问,可以使用旗语。
信箱:类似于fifo,再线程之间最数据通信或者内部数据缓存时可以考虑使用此元素。