zoukankan      html  css  js  c++  java
  • 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,"	Current 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,"	Current 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
    ",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,"	Triggering The Event");
            ->ev_1;
          end
         
          //process-2, wait for the event to trigger
          begin
            $display($time,"	Waiting for the Event to trigger");
            @(ev_1.triggered);
            $display($time,"	Event 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,"	Triggering The Event");
            ->ev_1;
          end
        
          //process-2, wait for the event to trigger
          begin
            $display($time,"	Waiting for the Event to trigger");
            wait(ev_1.triggered);
            $display($time,"	Event 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,"	Triggering The Event ev_1");
            ->ev_1;
          end
     
          //process-2, triggers the event ev_2
          begin
            #2;
            $display($time,"	Triggering The Event ev_2");
            ->ev_2;
          end
     
          //process-3, triggers the event ev_3
          begin
            #1;
            $display($time,"	Triggering 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,"	Waiting for the Event's to trigger");
            wait_order(ev_2,ev_1,ev_3)
              $display($time,"	Event's triggered Inorder");
            else
              $display($time,"	Event'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

  • 相关阅读:
    向Url发送post请求传递参数
    表格列转行
    C#匹配HTML中的图片地址
    C# 正则表达式(备忘录)
    将天文数字转换成中文大写
    搜索引擎优化排名因素小结
    WPF概述
    将中文汉字转换成拼音(全拼)
    提取网页中的链接并生成xml
    快速排序算法的实现
  • 原文地址:https://www.cnblogs.com/lyc-seu/p/12797089.html
Copyright © 2011-2022 走看看