SV -- Interprocess Communication (IPC 线程间通信)
作者:互联网
SV -- Interprocess Communication (IPC 线程间通信)
@(SV)
目录
1. Semaphore 旗语
- 旗语是sv内置的方法,可以用来做线程间的同步。
- 旗语就像一个桶,里面有很多键。使用旗语的进程必须首先从桶中获取一个密钥,然后才能继续执行,所有其他进程必须等待,直到向桶中返回足够数量的密钥。
- 设想这样一种情况:两个进程试图访问一个共享内存区域。其中一个进程试图写入,而另一个进程试图读取相同的内存位置。这导致了一个意想不到的结果。可以使用旗语来克服这种情况。
语法:semaphore semaphore_name;
方法:
- new(); 生成一定数量的keys
- get(); 从桶中获取一定数量的keys
- put(); 返回一定数量的keys到桶中
- try_get(); 尝试获取一个或多个keys,不会让线程阻塞
其中get和try_get的区别在于:
- get是在keys可获取时返回并且线程继续执行,而keys不可获取时线程被阻塞。
- try_get则不管keys是否可获取,线程都会继续执行,只是keys可获取时返回1,不可获取返回0。
实例:并行进程之间通过旗语顺序执行
module semaphore_ex;
semaphore sema; //declaring semaphore sema
initial begin
sema=new(4); //creating sema with '4' keys
fork
display(); //process-1
display(); //process-2
display(); //process-3
join
end
//display method
task automatic display();
sema.get(2); //getting '2' keys from sema
$display($time,"\tCurrent Simulation Time");
#30;
sema.put(2); //putting '2' keys to sema
endtask
endmodule
上面例子输出:
0 Current Simulation Time
0 Current Simulation Time
30 Current Simulation Time
第三个进程需要等待前两个中一个归还了keys之后才能执行。
下面是有多个keys存取的情况:
module semaphore_ex;
semaphore sema; //declaring semaphore sema
initial begin
sema=new(4); //creating sema with '4' keys
fork
display(2); //process-1
display(3); //process-2
display(2); //process-3
display(1); //process-4
join
end
//display method
task automatic display(int key);
sema.get(key); //getting 'key' number of keys from sema
$display($time,"\tCurrent Simulation Time, Got %0d keys",key);
#30;
sema.put(key); //putting 'key' number of keys to sema
endtask
endmodule
桶内只有四个键,会先依次取,第一个进程取了两个,第二个取三个不够,第三个可以取,此时进程1和3先执行,执行完后进程4和2再执行。
2. Mailbox 信箱
邮箱是一种通信机制,它允许在进程之间交换消息。希望与另一个进程通信的进程将消息发送到邮箱,邮箱将消息临时存储在系统定义的内存对象中,以便将消息传递给所需的进程。
mailbox按size分可以分为两种:
- bounded mailbox
- unbounded mailbox
有界邮箱的大小已定义。邮箱在存储有限数量的消息时变为满的。试图将消息放入完整邮箱的进程将被挂起,直到邮箱队列中有足够的空间可用为止。
无界邮箱的大小无限。
按照类型也可分为两种:
- Generic Mailbox (type-less mailbox) 通用邮箱
mailbox mailbox_name;
- Parameterized mailbox (mailbox with particular type) 参数化邮箱
mailbox#(type) mailbox_name;
跟旗语类似,信箱也有如下几种方法:
new(); - Create a mailbox
put(); - Place a message in a mailbox
try_put(); - Try to place a message in a mailbox without blocking
get(); or peek();- Retrieve a message from a mailbox
num(); - Returns the number of messages in the mailbox
try_get(); or try_peek(); - Try to retrieve a message from a mailbox without blocking
案例:
mailbox负责在generator和driver之间传输数据:
//-------------------------------------------------------------------------
// Packet
//-------------------------------------------------------------------------
class packet;
rand bit [7:0] addr;
rand bit [7:0] data;
//Displaying randomized values
function void post_randomize();
$display("Packet::Packet Generated");
$display("Packet::Addr=%0d,Data=%0d",addr,data);
endfunction
endclass
//-------------------------------------------------------------------------
//Generator - Generates the transaction packet and send to driver
//-------------------------------------------------------------------------
class generator;
packet pkt;
mailbox m_box;
//constructor, getting mailbox handle
function new(mailbox m_box);
this.m_box = m_box;
endfunction
task run;
repeat(2) begin
pkt = new();
pkt.randomize(); //generating packet
m_box.put(pkt); //putting packet into mailbox
$display("Generator::Packet Put into Mailbox");
#5;
end
endtask
endclass
//-------------------------------------------------------------------------
// Driver - Gets the packet from generator and display's the packet items
//-------------------------------------------------------------------------
class driver;
packet pkt;
mailbox m_box;
//constructor, getting mailbox handle
function new(mailbox m_box);
this.m_box = m_box;
endfunction
task run;
repeat(2) begin
m_box.get(pkt); //getting packet from mailbox
$display("Driver::Packet Recived");
$display("Driver::Addr=%0d,Data=%0d\n",pkt.addr,pkt.data);
end
endtask
endclass
//-------------------------------------------------------------------------
// tbench_top
//-------------------------------------------------------------------------
module mailbox_ex;
generator gen;
driver dri;
mailbox m_box; //declaring mailbox m_box
initial begin
//Creating the mailbox, Passing the same handle to generator and driver,
//because same mailbox should be shared in-order to communicate.
m_box = new(); //creating mailbox
gen = new(m_box); //creating generator and passing mailbox handle
dri = new(m_box); //creating driver and passing mailbox handle
$display("------------------------------------------");
fork
gen.run(); //Process-1
dri.run(); //Process-2
join
$display("------------------------------------------");
end
endmodule
输出:
Packet::Packet Generated
Packet::Addr=3,Data=38
Generator::Packet Put into Mailbox
Driver::Packet Recived
Driver::Addr=3,Data=38
Packet::Packet Generated
Packet::Addr=118,Data=92
Generator::Packet Put into Mailbox
Driver::Packet Recived
Driver::Addr=118,Data=92
3. Event 事件
事件是对流程之间的同步非常有用的静态对象。事件操作是两个分阶段的流程,其中一个流程将触发事件,另一个流程将等待触发事件。
- 事件使用->操作符或->>操作符触发
- -> : 触发一个事件时解除当前等待该事件的所有进程的阻塞。
- ->> : 非阻塞事件使用->>操作符触发
- 使用@操作符或wait()来等待触发事件
- @: 对于使用一个使用触发来解除等待事件的进程的阻塞,等待进程必须在触发进程执行触发器操作符->之前执行@语句
- wait(): 如果带有@操作符的事件触发和等待事件触发同时发生,@操作符可能会错过检测事件触发。
wait(event_name.triggered);
- wait_order(): 构造将阻塞该进程,直到按照给定的顺序(从左到右)触发所有指定的事件。无序的事件触发器将不会解除对进程的阻塞。
wait_order(a,b,c);
还可以这么写:wait_order( a, b, c ) success = 1; else success = 0;
表示当触发顺序不是abc时,会显示错误。
示例:@ .triggered
module events_ex;
event ev_1; //declaring event ev_1
initial begin
fork
//process-1, triggers the event
begin
#40;
$display($time,"\tTriggering The Event");
->ev_1;
end
//process-2, wait for the event to trigger
begin
$display($time,"\tWaiting for the Event to trigger");
@(ev_1.triggered);
$display($time,"\tEvent triggered");
end
join
end
endmodule
输出:
0 Waiting for the Event to trigger
40 Triggering The Event
40 Event triggered
上面的例子中,->ev_1需要发生在triggered之后,即使同一时间发生也不会识别到。
示例:wait(.triggered)
module events_ex;
event ev_1; //declaring event ev_1
initial begin
fork
//process-1, triggers the event
begin
$display($time,"\tTriggering The Event");
->ev_1;
end
//process-2, wait for the event to trigger
begin
$display($time,"\tWaiting for the Event to trigger");
wait(ev_1.triggered);
$display($time,"\tEvent triggered");
end
join
end
endmodule
输出:
0 Triggering The Event
0 Waiting for the Event to trigger
0 Event triggered
上面的例子中,->ev_1可以和wait同一时间发生。
示例: wait_order()
module events_ex;
event ev_1; //declaring event ev_1
event ev_2; //declaring event ev_2
event ev_3; //declaring event ev_3
initial begin
fork
//process-1, triggers the event ev_1
begin
#6;
$display($time,"\tTriggering The Event ev_1");
->ev_1;
end
//process-2, triggers the event ev_2
begin
#2;
$display($time,"\tTriggering The Event ev_2");
->ev_2;
end
//process-3, triggers the event ev_3
begin
#1;
$display($time,"\tTriggering The Event ev_3");
->ev_3;
end
//process-4, wait for the events to trigger in order of ev_2,ev_1 and ev_3
begin
$display($time,"\tWaiting for the Event's to trigger");
wait_order(ev_2,ev_1,ev_3)
$display($time,"\tEvent's triggered Inorder");
else
$display($time,"\tEvent's triggered Out-Of-Order");
end
join
end
endmodule
输出:
0 Waiting for the Event's to trigger
1 Triggering The Event ev_3
1 Event's triggered Out-Of-Order
2 Triggering The Event ev_2
6 Triggering The Event ev_1
标签:event,IPC,keys,Communication,mailbox,间通信,ev,display,Event 来源: https://www.cnblogs.com/lyc-seu/p/12797089.html