systemverilog-线程的使用与通信

1.并发线程

1.fork-join、fork-join_any 和 fork-join_none

在这里插入图片描述

//父线程
fork 
	statement 1;//子线程
	statement 2;//子线程
	statement 3;//子线程
join | join_any |join_none
statement 4;
  • join 子线程并行执行,必须在线程statement4执行之前完成
  • join _any 子线程并行执行,必须有一个子线程完成,线程statement4才能执行
  • join_none 线程statement4不会被阻塞,它与statement1,2,3同时执行

1.2 wait fork与disable fork

wait fork 等待所有子线程结束
在SV中,当程序中的initial块全部执行完毕,仿真器退出。这时fork-join_anyfork-join_none中的内容可能还没执行完。
如果希望等待fork块中所有线程执行完毕再退出结束initial块,我们可以使用wait fork来等待所有子线程结束。

task run_threads;
	...
	fork
		check_trans(tr1);//线程1
		check_trans(tr2);//线程2
	join_none
	...
	//等待所有fork中的线程结束再退出
	wait fork;
endtask

停止一个单线程
在使用了fork-join_any或者fork-join_none以后,我们可以使用disable来指定需要停止的线程

task check_trans(Transaction tr)
	fork
	begin
		fork:timeout_block
			begin
				$diaplay("%0t:Addr match %d",$time,tr.addr);
			end
		join_any
		//关掉timeout_block这个线程
		disable timeout_block
	end
	join_none
endtask

停止多个线程
disable fork可以停止从当前线程中衍生出来的所有子线程

initial begin
	check_trans(tr0);//线程0
	//创建一个线程来限制disable fork的作用范围
	fork //线程1
		begin
			check_trans(tr1);//线程2
			fork//线程3
				check_trans(tr2);//线程4
			join
			//停止线程1-4,单独保留线程0
			#(TIME_OUT/2) disable fork;
		end
	join
end

2.事件

event事件是静态对象,用于线程之间的同步。

  • 事件触发操作符:->
  • 等待事件操作符 :@ 为边沿触发,wait() 为电平敏感;
  • triggered函数,用于检查一个事件是否被触发过,而不要求事件等待与触发的先后顺序,是对 @ 等待事件的增强
  • wait(event_name.triggered) 如果当前的仿真时间范围内,事件曾被触发过,则语句不会被阻塞,否则,该语句会一直等待事件被触发。
    event的边沿阻塞:
event e1,e2;
initial begin
	$display("@%0t: 1:before trigger",$time);
	-> e1;
	@e2;
	$display("@%0t: 1:after trigger",$time);
end
initial begin
	$display("@%0t: 2:before trigger",$time);
	-> e2;
	@e1;
	$display("@%0t: 2:after trigger",$time);
end

结果:
在这里插入图片描述
可以看出:
第一个初始块启动,触发e1事件,然后阻塞在e2事件;
第二个初始块启动,触发e2事件,然后阻塞在e1事件
e1和e2在同一时刻被触发,但由于delta cycle的时间差使得两个初始化块无法等到e1和e2。
所以更安全的方式可以使用event的方法triggered(),它比@更有能力保证,只要event被触发过,就可以防止引起阻塞。

event e1,e2;
initial begin
	$display("@%0t: 1:before trigger",$time);
	-> e1;
	wait(e2.triggered());
	$display("@%0t: 1:after trigger",$time);
end
initial begin
	$display("@%0t: 2:before trigger",$time);
	-> e2;
	wait(e1.triggered());
	$display("@%0t: 2:after trigger",$time);
end

在这里插入图片描述
2.event的合并
当把一个事件赋值给另一个事件时,两个事件合并为一个事件,一个事件触发,另一个事件也会触发。

event a,b;
a=b;//事件a与事件b进行合并
-> a;//触发a时间的同时,b事件也会被触发

3.旗语

  • semaphore可以实现对同一资源的访问控制
    对于初学者,无论线程之间在共享什么资源都应该使用semaphone等资源访问控制的手段,以此避免可能出现的问题。
方法释义
new()创建一个带单个或多个钥匙的旗语,默认为0
get()获取一个或多个钥匙的旗语,默认为1
put()返回一个或多个钥匙的旗语,默认为1
try_get()获取一个旗语而不被阻塞,返回1表示有足够多的钥匙,返回0表示钥匙不够

对于线程间共享资源的使用方式,应该遵循互斥访问原则,来对访问进行控制。

class car;
	semaphore key;
	function new();
		key = new(1);
	endfunction
	task get_on(string p);
		$display("%s is waiting for the key",p);
		key.get();
		#1ns;
		$display("%s got on the car",p);
	endtask
	task get_off(string p);
		$display("%s got off the car",p);
		key.put();
		#1ns;
		$display("%s returned the key",p);
	endtask
endclass
module family;
car byd = new();
string p1 = "husband";
string p2 = "wife";
initial begin
	fork
		begin //丈夫开车
			byd.get_on(p1);
			byd.get_off(p1);
		end
		begin//妻子开车
			byd.get_on(p2);
			byd.get_off(p1);
		end
	join
end
endmodule

4.mailbox信箱

mailbox数据传输的媒介,mailbox可以在不同的线程之间传递信息,将一个线程中的数据,通过mailbox传递给另一个进程;当mailbox中没有数据时,线程将等待。
mailbox可以设置一定的深度,当信箱中的信息数量达到信箱的深度,信箱满,此时不能在信箱中存放东西。

  • mailbox和队列queue有相近之处
  • mailbox是一种对象,因此也需要使用new()来例化。如果size是0或者没有指定,则信箱是无限大的,可以容纳任意多的条目。
方法释义
put()把数据放入信箱
get()把数据从信箱移除
peek()可以获取对信箱里数据的拷贝而不移除它
try_put()把数据存入信箱而不发生阻塞
try_get()try_peek()试图获得信箱数据而不发生阻塞
num()返回信箱中的数据条目
//声明句柄
mailbox mailbox_name; //创建信箱
//创建对象
mailbox_name = new();//创建一个无容量限制的信箱
mailbox_name = new(m_size);//创建一个定容信箱
program automatic bounded;
	mailbox mbox;
	initial begin
	mbx = new(1);
	fork
		for(int i=1;i<4;i++) begin
			$display("Produce:before put(%0d)",i);
			mbx.put(i);
			$display("Produce:after put(%0d)",i);
		end
		repeat(4) begin
			int j;
			#1ns mbx.get(j);
			$display("Consumer:after get(%0d)",j);
		end
	join
	end	
endprogram
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值