1 单向通信

单向通信 (unidirectional communication) 指的是从 initiator 到 target 的数据流向是单一方向的, 或者 initiator 和 target 只能扮演 producer 和 consumer 中的一个角色。

在UVM中,单数据流向的 TLM 端口有很多类型(部分):

uvm_blocking_put_PORT 

uvm_nonblocking_put_PORT

uvm_put_PORT 

uvm_blocking_get_PORT 

uvm_nonblocking_get_PORT 

uvm_get_PORT 

uvm_blocking_peek_PORT 

uvrn_nonblocking_peek_PORT

uvm_peek_PORT 

uvrn_blocking_get_peek_PORT

uvm_nonblocking_get_peek_PORT

uvm_get_peek_PORT 

按照 UVM 端口名的命名规则, 它们指出了通信的两个要素:

•    是不是阻寒的方式(即可以等待延时);
•    何种通信方法。

 单向通信--方法

•    阻塞传输方式将blocking前缀作为函数名的一部分, 而非阻塞方式则名为nonblocking。 阻塞端口的方法类型为task, 这保证了可以实现事件等待和延时;非阻塞端口的力式类型为function, 这确保了方法调用可以立即返回。
•    我们从方法名也可以发现, 例如uvm_blocking_put_PORT提供的方法 task put()会在数据传送完后返回,uvm_nonblocking_put_PORT对应的两个函数try_put()和can_put()是立刻返回的。
•    uvm_put_PORT则分别提供了blocking和nonblocking的方法, 这为通讯方式提供了更多选择。blocking阻塞传输的方法包含:

•   Put (): initiator先生成数据T t, 同时将该数据传送至target。

•   Get(): initiator从target获取数据T t, 而target中的该数据T t则应消耗。

•   Peek(): initiator从target获取数据Tt, 而target中的该数据T t还应保留。

与上述三种任务对应的nonblocking非阻塞方法分别是:

•    try/can_put()
•    try/can_get()
•    try/can_peek()

•   这六个非阻塞函数与对应阻塞任务的区别在于,它们必须立即返回, 如果try_xxx函数可以发送或者获取数据, 那么函数应该返回1, 如果执行失败则应返回0。
•    或者通过can_xxx函数先试探target是否可以接收数据, 如果可以, 再通过try_xxx函数发送, 提高数据发送的成功率。

class itrans extends uvm_transaction;int id; int data;...endclass class otrans extends uvm_transaction;int id; int data;...endclass class compl extends uvm_component;uvm_blocking_put_port #(itrans) bp_port;//定义阻塞型端口uvm_nonblocking_get_port #(otrans) nbg_port;//定义非阻塞型端口`uvm_component_utils(compl)//注册...task run_phase(uvm_phase phase);itrans itr;otrans otr;int trans_num = 2; fork beginfor(int i=0; i<trans_num; i++) beginitr = new ("itr", this); itr.id = i; itr.data = 'hlO + i; this.bp_port.put(itr); 'uvm_info ("PUT", $sformatf("put itrans id: 'h%0x , data:'h%0x",tr.id, itr.data), UVM_LOW)end end beginfor(int j=O; j<trans_num; j++) beginforever beginif(this.nbg_port.try_get(otr) == 1) break;else #lns; end `uvm_info("TRYGET", $sformatf("get otrans id: 'h%0x , data:'h%0x", otr.id, otr.data), UVM LOW)endend join endtask endclass class comp2 extends uvm_component;uvm_blocking_put_imp #(itrans, comp2) bp_imp; //定义阻塞型端口(target)uvm_nonblocking_get_imp #(otrans, comp2) nbg_imp; //定义阻塞型端口(target)itrans itr_q[$]; `uvm_component_utils(comp2)...task put(itrans t); itr_q.push back(t);endtask function bit try_get (output otrans t);itrans i; if(itr_q.size() != 0) begini = itr_q.pop_front (); t = new("t", this);t.id = i.id;t.data = i.data << 8;return l;endelse return 0;endfunction function bit can_get();if(itr_q.size() != 0) return l; else return 0; endfunction endclass class envl extends uvm_env;compl cl; comp2 c2; `uvm_component_utils(envl) function void build_phase(uvm_phase phase);super.build_phase(phase); cl = compl::type_id::create("cl", this); c2 = comp2::type_id::create("c2", this);endfunction: build_phase function void connect_phase(uvm_phase phase);super.connect_phase(phase); cl.bp_port.connect(c2.bp_imp); cl.nbg_port.connect(c2.nbg_imp);//端口连接endfunction: connect_phaseendclass

首先comp1例化了两个port端口:
•     uvm_blocking_put_port #(itrans) bp_port; 
•     uvm_nonblocking_get_port #(otrans) nbg_port;

comp2作为target则相应例化了两个对应的imp端口:
•     uvm_blocking_put_imp #(itrans, comp2) bp_imp; 
•     uvm_nonblocking_get_imp #(otrans, comp2) nbg_imp;

env1环境将comp1与comp2连接之前, 需要在comp2中实现两个端口对应的方法:
•     task put(itrans t) 
•     function bit try_get (output otrans t) 
•     function bit can_get();

接下来env1对两个组件的端口进行了连接, 这使得comp1在run phase可以通过自身端口间接调用comp2中定义的端口方法。

因此在调用端口方法之前的几个步骤是必不可少的:
•    定义端门
•    实现对应方法
•    在上层将端口进行连接

2 多向通信

与单向通信相同的是,双向通信(bidirectional communication)的两端也分为initiator和target,但是数据流向在端对端之间是双向的。
双向通信中的两端同时扮演着producer和consumer的角色, 而initiator作为request发起方, 在发起request之后, 还会等待response返回。

UVM双向端口分为以下类型:
•     uvm_blocking_transport_PORT
•     uvm_nonblocking_transport_PORT
•     uvm_transport_PORT
•     uvm_blocking_master_PORT 
•     uvm_nonblocking_master_PORT 
•     uvm_master_PORT 
•     uvm_blocking_slave_PORT 
•     uvm_nonblocking_slave_PORT 
•     uvm_slave_PORT 

双向端口按照通信握手方式可以分为:

•    transport双向通信方式
•    master和slave双向通信方式

transport端口通过transport()方法, 可以在同一方法调用过程中完成REQ 和RSP的发出和返回。
 master和slave的通信方式必须分别通过put、 get和peek的调用, 使用两个方法才可以完成一次握手通信。
master端口和slave端门的区别在于,当initiator作为master时, 它会发起REQ送至target端, 而后再从target端获取RSP; 当initiator使用slave端口时,它会先从target端获取REQ, 而后将RSP送至target端。

class compl extends uvm_component;uvm_blocking_transport_port #(itrans, otrans) bt_port;//定义一个transport双向端口`uvm_component_utils (compl)//注册...task run_phase(uvm_phase phase);itrans itr; otrans otr; int trans_num = 2; for(int i=0; i<trans_num; i++) beginitr = new ("itr", this); itr.id = i; itr.data = 'hlO + i; this.bt_port.transport(itr, otr); `uvm info("TRSPT", $sformatf("put itrans id: 'h%0x , data: 'h%0xet otrans id:'h%0x , data: 'h%0x ",itr.id, itr.data, otr.id, ctr.data), UVM_LOW)end endtaskendclass class comp2 extends uvm_component;uvm_blocking_transport_imp #(itrans, otrans, comp2) bt_imp; //定义一个transport双向端口target'uvm_component_utils(comp2) //注册task transport(itrans req, output otrans rsp); rsp = new("rsp", this); rsp.id = req.id; rsp.data = req.data << 8;endtask
endclass class envl extends uvm_env;compl cl;comp2 c2; uvm_component_utils(envl) ...function void build_phase(uvm_phase phase);super.build_phase(phase); cl= compl::type_id: :create("cl", this); c2= comp2::type_id: :create("c2", this);//例化endfunction: build_phase function void connect_phase(uvm_phase phase);super.connect_phase(phase); cl.bt_port.connect(c2.bt_imp);//连接endfunction: connect_phase endclass

从上面代码可以看出,双向端口处理类似于单向端口的是端口例化和连接, 不同的只是要求实现对应的双向传输任务:

task transport (itrans req, output otrans rsp)

3 多向通信

多向通信(multi-directional communication)这个概念听起来容易让读者产生歧义, 因为这种方式服务的仍然是两个组件之间的通信, 而不是多个组件之间的通信, 毕竟多个组件的通信仍然可以由基础的两个组件的通信方式来构建。
多向通信指的是, 如果initiator与target之间的相同TLM端口数目超过一个时的处理解决办法。

comp1有两个uvm_blocking_put_port, 而comp2有两个uvm_blocking_put_imp端口, 我们对于端口例化可以给不同名字, 连接也可以通过不同名字来索引, 但问题在于comp2中需要实现两 一
个task put (itrans t), 又因为不同端口之间要求在imp端口侧实现专属方法, 这就造成了方法命名冲突, 即无法在comp2中定义两个同名的put任务。

UVM通过端口宏声明方式来解决这一问题, 它解决问题的核心在于让不同端口对应不同名的任务, 这样便不会造成方法名的冲突。 UVM 为解决多向通信问题的宏按照端口名的命名方式分为:

`uvm_blocking_put_imp_decl(SFX)

`uvm_nonblocking_put_imp_decl(SFX)

`uvm_put_imp_decl(SFX)

`uvm_blocking_get_imp_decl(SFX)

`uvm_nonblocking_get_imp_decl(SFX)

`uvm_get_imp_decl(SFX)

`uvm_blocking_peek_imp_decl(SFX)

`uvm_nonblocking_peek_imp_decl(SFX)

`uvm_peek_imp_decl(SFX)

`uvm_blocking_get_peek_imp_decl(SFX) 

`uvm_nonblocking_get_peek_imp_decl(SFX) 

`uvm_get_peek_imp_decl(SFX) 

`uvm_blocking_transport_imp_decl(SFX) 

`uvm_nonblocking_transport_imp_decl(SFX) 

`uvm_transport_imp_decl(SFX) 

`uvm_blocking_master_imp_decl(SFX) 

`uvm_nonblocking_master_imp_decl(SFX) 

`uvm_master_imp_decl(SFX) 

`uvm_blocking_slave_imp_decl(SFX) 

`uvm_nonblocking_slave_imp_decl(SFX) 

`uvm_slave_imp_decl(SFX) 

`uvm_blocking_put_imp_decl(_pl)
`uvm_blocking_put_imp_decl(_p2)//定义了两个宏,为了target声明端口避免冲突
class compl extends uvm_component;uvm_blocking_put_port #(itrans) bp_portl;uvm_blocking_put_port #(itrans) bp_port2;`uvm_component_utils (compl)...task run_phase(uvm_phase phase);itrans itrl, itr2; int trans_num = 2;fork for(int i=0; i<trans_num; i++) beginitrl = new("itrl",this); itrl.id = i; itrl.data='hl0 + i ; this.bp_portl.put(itrl);end for(int i=0; i<trans_num; i++) beginitr2 = new("itr2", this); itr2.id ='hl0 + i; itr2.data ='h20 + i;this.bp_port2.put(itr2); end join endtask
endclass class comp2 extends uvm_component;
uvm_blocking_put_imp_pl #(itrans, comp2) bt_imp_pl; //注意bt_imp_pl加了_p1
uvm_blocking_put_imp_p2 #(itrans, comp2) bt_imp_p2;
itrans itr_q[$];
semaphore key; //用了semaphore,顺序上有了限定
`uvm_component_utils (comp2)
...
task put_pl(itrans t);
key.get();
itr q.push back(t);
uvm_info("PUTPl", $sformatf("put itrans id: 'h%0x , data: 'h%0x",t.id, t.data), UVM_LOW)
key.put();
endtask
task put_p2(itrans t); //注意put_p2加了_p1
key.get() ;
itr q.push back(t);
`uvm_info("PUTP2", $sformatf("put itrans id: 'h%Ox , data: 'h%Ox",t.id, t.data), UVM_LOW)
key.put();
endtask
endclass class envl extends uvm_env;
compl cl;
comp2 c2;
`uvm_component_utils (env1)
...
function void build_phase(uvm_phase phase);
super.build_phase(phase);
cl = compl::type_id::create("cl", this);
c2 = comp2::type_id::create ("c2",this);
endfunction: build_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
c1.bp_portl.connect(c2.bt_imp_pl);
c1.bp_port2.connect(c2.bt_imp_p2);
endfunction: connect_phase
endclass //仿真结果:uvm_test_top.env.c2 [PUTPl] put itrans id: 'h0 , data: 'hl0uvm_test_top.env.c2 [POTPl) put itrans id: 'hl , data: 'hll uvm_test_top.env.c2 [PUTP2] put itrans id: 'hl0, data: 'h20 uvm_test_top.env.c2 (PUTP2] put itrans id: 'hll, data: 'h21

当一个组件的两个端口通过相同方法(比如task put())向另一个组件传输数据时, 需要使用上述的宏, 分别声明两个不同的 imp 类型, 完整的实现步骤包括:

•    选择正确的 imp 宏来定义不同的 imp 端口类型, 而宏的参数 SFX (后缀名)也会转化为相应的 imp 端口类型名。
•    在 imp 例化的组件中, 分别实现不同的 put_SFX 方法。
•    在 port 例化的组件中,不需要对目标imp端口类型进行区分,例如compl 中的 bp_portl和 bp_port2 为相同的端口类型。
•    对于 comp 调用 put()方法, 它只需要选择 bp_port1 或 bp_port2, 而不需要更替 put()方法名, 即仍然按照 put()来调用而不是 put_pl()或 put_p2()。
•    在上层环境应该连接 comp1 和 comp2 的 TLM端口。

用户只需要在例化多个imp端口的组件中实现不同名称的方法,使其与对应imp类型名保持一致。而对于port端口一侧的组件,则不需关心调用的方法名称,因为该方法名并不会发生改变。所以通过这种方式可以防止通信方法名的冲突,从而解决多向通信的问题。

4 通信管道

TLM通信的实现方式, 这些通信有一个共同的地方即都是端对端的, 同时在target一端需要实现传输方法, 例如put()或者get()。

对于monitor、 coverage collector等组件在传输数据时, 会存在一端到多端的传输, 如何解决这一问题?
几个TLM组件和端口可以帮助用户免除这些烦恼:

•    TLM FIFO
•    analysis port
•    analysis TLM FIFO
•    request & response 通信管道

在 一般TLM传输过程中, 无论是initiator给target发起一个 transaction, 还是initiator从target获取一 个transaction, transaction 最终都会流向consumer中(initiator和target都可以是consumer)。

TLM FIFO

consumer在没有分析transaction时, 我们希望将该对象先存储到本地FIFO中供稍后使用。

.用户需要分别在两个组件中例化端口, 同时在target中实现相应的传输方法。
.多数情况下, 需要实现的传输方法都是相似的, 方法的主要内容即是为了实现一个数据缓存功能。

TLM FIFO uvm_tlm_fifo类是一个新组件, 它继承于uvm_component 类, 而且已经预先内置了多个端口以及实现了多个对应方法供用户使用。

一个 uvm_ tlm _ fifo 会包含多个 TLM 端口, 我们摘出常用端口:

•    put_export: 用户可以通过该端口调用 put() 、 try_put() 、 can_put()。
•    put_ap: 调用了put()方法写入的数据同时也会通过该端口的 write()函数送出。
•    get_peek_export: 用户可以通过该端口调用 get() 、 try_get() 、can_get() 、 peek() 、 try_peek()、 can_peek()。
•    get_ap: 调用了 get()和 peek()方法读出的数据也会通过该端口的 write() 函数送出。

uvm_tlm_fifo的功能类似于mailbox,不同的地方在于uvm_tlm_fifo提供了各种端口供用户使用。我们推荐在initiator端例化put_port或者get_peek_port, 来匹配uvm_tim_fifo的端口类型。如果用户例化了其它类型的端口, uvm_tlm_fifo还提供put、get以及peek对应的端口:

uvm_put_imp #(T, this_type) blocking_put_export;

uvm_put_imp #(T, this_type) nonblocking_put_export;

uvm_get_peek_imp #(T, this_type) blocking_get_export; 
uvm_get_peek_imp #(T, this_type) nonblocking_get_export;

uvm_get_peek_imp #(T, this_type) get_export; 
uvm_get_peek_imp # (T, this_type) blocking_peek_export; 
uvm_get_peek_imp #(T, this_type) nonblocking_peek_export;

uvm_get_peek_imp #(T, this_type) peek_export; 
uvm_get_peek_imp #(T, this_type) blocking_get_peek_export;

uvm_get_peek_imp #(T, this_type) nonblocking_get_peek_export;

 Analysis Port

除了端对端的传输, 在一些情况下还有多个组件会对同一个数据进们运算处理。
如果这个数据是从同一个源的TLM端口发出到达不同组件, 这就要求该种端口可以满足从一端到多端的需求。
如果数据源端发生变化需要通知跟它关联的多个组件时, 我们可以利用软件的设计模式之一观察者模式(observer pattern)来实现。

observer pattern 的核心在于, 第一, 这是从一个 initiator 端到多个 target 端的方式;第二, analysis port 采取的是 "push" 模式, 即从 initiator 端调用多个 target 端的 write()函数实现数据传输。

initiator.ap.connect(target1. aimp); 
initiator.ap.connect(target2.aimp); 
initiator.ap.connect(target3.aimp);

一个典型的 analysis port 类型端口的连接方式, 类似于其他 TLM 端口的是, 按照传输方法和端口方向组合可以将 analysis port分为uvm_ analysis _port、uvm_analysis_ export 以及 uvm_analysis_imp。 target 一侧例化了 uvm_analysis_imp 后还需要实现 write()函数。 最后, 在顶层可以将 initiator 端的 uvm _ analysis _port 同多个 target 端的 uvm_analysis_ imp 进行连接。 在 initiator 端调用wirte()函数时, 实际上它是通过循环的方式将所有连接的 target 端内置的 write()函数进行了调用。由于函数立即返回的特点, 无论连接多少个 target 端, initiator 端调用 write()函数总是可以立即返回的。这里稍微不同于之前单一端口函数调用的是,即使没有target 与之相连,调用 write() 函数时也不会发生错误。

 Analysis TLM FIFO

由于 analysis 端口实现了一端到多端的 TLM 数据传输,一个新的数据缓存组件类uvm_tlm_analysis_fifo为用户提供了可以搭配 uvm_analysis_port 端口、 uvm_analysis_imp 端口 和write()函数. uvm_tlm_analysis_fifo 类继承于 uvm_tlm_fifo, 这表明它本身具有面向单一 TLM 端口的数据缓存特性, 同时该类又有一个 uvm_analysis_imp 端口 analysis_ export 且实现了 write()函数:

uvm_analysis_imp #(T, uvm_tlm_analysis_fifo #(T)) analysis_export;

基于 initiator 到多个 target 的连接方式,用户如果想轻松实现一端到多端的数据传输,可以下图那样插入多个 uvm_ tlm _analysis_ fifo。这里给出连接方式:

•    将initiator的analysis port连接到tlm_analysis_fifo的get_export端口,这样数据可以从initiator发起, 写入到各个tlm_analysis_fifo的缓存中。
•    将多个target的get_port连接到tlm_analysis_fifo的get_export, 注意保持端口类型的匹配,这样从target一侧只需要调用get()方法就可以得到先前存储在 tlm_analysis_fifo中的数据。

initiator.ap.connect(tlm_analysis_fifol.analysis_export);

target1.get_port.connect(tlm_analysis_fifol.get_export);
initiator.ap.connect(tlm_analysis_fifo2.analysis_export);

target2.get_port.connect(tlm_analysis_fifo2.get_export);
initiator.ap.connect(tlm_analysis_fifo3.analysis_export);

target3.get_port.connect(tlm_analysis_fifo3.get_export);

 Request&Response 通信管道

双向通信端口 transport, 即通过在 target 端实现 transpo()方法可以在一次传输中既发送 request 又接收 response。

UVM提供了两种简便的通信管道, 它们作为数据缓存区域, 既有TLM端口从外侧接收request和response, 同时也有TLM端口供外侧获取request和response。 这两种TLM通估管道分别是:
•    uvm_tlm_req_rsp_channel
•    uvm_tlm_transport_channel

uvm_tlm_req_rsp_channel 提供的端口首先是单一方向的,为了让端口列表清爽一些,下面只列出该类的例化端口:

•    uvm_put_export # (REQ) put_request_export;
•    uvm_put_export # (RSP) put_response_export;
•    uvm_get_peek_export # (RSP) get_put_peek_response_export;
•    uvm_get_peek_export # (REQ) get_peek_request_export;
•    uvm _ analysis_port #(REQ) request_ap; 
•    uvm _ analysis_port #(RSP) response_ap;
•    uvm_master_imp#(REQ, RSP, this_type, uvm_tlm_fifo # (REQ), uvm_tlm_fifo #(RSP)) master_export;
•    uvm_slave_imp # (REQ, RSP, this_type, uvm _ tlm _ fifo # (REQ) , uvm_tlm_fifo#(RSP)) slave_export;

有了这么多丰富的端口, 用户可以在使用成对的端口进行数据的存储和访问。 需要注意
的是, uvm_tlm _req_rsp _ channel 内部例化了两个 mailbox 分别用来存储 request 和 response:

protected uvm_tlm_fifo#(REQ) m_request_fifo;

protected uvm_tlm_fifo #(RSP) m_response_fifo;

例如, initiator 端可以连接 channel 的 put_request_export, target 连接 channel的 get_peek_ request_ export, 同时 target 连接 channel 的 put_response_ export, initiator 连接 channel 的 get_peek _response_ export 端口。 如下图 所示, 这种对应使得 initiator 与 target 可以利用 uvrn_tlm_req__rsp_channel 进行 request与response 的数据交换。

通过这种对应的方式, 使得initiator与target可以利用uvm_tlm_req_rsp_channel进行request与response的数据交换。

initiator.put_port.connect(req_rsp_channel.put_request_export);
target.get_peek_port.connect(req_rsp_channel.get_peek_request_export);
target.put_port.connect(req_rsp_channel.put_response_export);
initiator.get_peek_port.connect(req_rsp_channel.getpeek_response_export);

或者, 也可以利用另一种连接方式,如下:

initiator.master_port.connect(req_rsp_channel.master_export);
target.slave_port.connect(req_rsp_channel.slave_export);

通过所述的这些方式,我们可以实现initiator与target之间自由的request和 response传输,而这两种连接方式仍然需要分别调用两次方法才可以完成 request和response的传输。
在uvm_tlm_req_rsp _channel的基础上, UVM又添加了具备transport端口的管道组件uvm_tlm_transport_channel类。 它继承于uvm_tlm_req_rsp_channel, 并且新例化了transport端口:

uvm_transport_imp # (REQ, RSP, this_type) transport_export;

新添加的这个 TLM FIFO 组件类型是针对于一些无法流水化处理的 request 和 response传输, 例如 initiator 端要求每次发送完 request, 必须等到 response 接收到以后才可以发送下一个 request, 这时 transport()方法就可以满足这一需求。如果将上面的传输方式进行修改,那么可以得到下图的连接方式:

需要变化的是initiator 端到req_rsp_ channel 的连接, 应该修改为:

initiator.transport_port.connect(transport_channel.transport_export)

至于transport_channel和target之间的连接, 则可以仍然保留之前的单向传输连接方式。

UVM--单向通信、双向通信、多向通信和通信管道相关推荐

  1. linux程序间管道通信,linux进程间通信——管道 详解

    管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入.常说的管道多是指无名管道, 无名管道只能用于具有亲缘关系的进程之间,这是它与有名管道的最大区别. 有名管道叫nam ...

  2. linux----------2--3----(无名)管道通信原理及管道编程实战

    IPC的方式通常有管道(无名管道和命名管道),消息队列,信号量,共享存储,socket,streams等,其中socket和streams支持以不同主机上的两个进程IPC.(笔试题或面试可能会考,记住 ...

  3. 进程通信之二 管道技术第二篇 匿名管道

    上一篇<进程通信之二 管道技术第一篇 输入输出的重定向>示范了增加若干程序代码来完成程序输入输出的重定向,并提出了如果没有程序源代码,只有程序文件如何来完成重定向.本篇就介绍如何使用匿名管 ...

  4. 命名管道(FIFO) Linux进程进程间的通信之命名管道(FIFO)

    Linux进程进程间的通信之命名管道(FIFO) 命名管道(FIFO),它和一般的管道一样.都是作为中间的邮递员来实现两个进程间的通信交流. 命名管道(FIFO)有几个特点: 1.命名管道(FIFO) ...

  5. Linux系统无名管道通信实验,Linux进程间通信(二)---管道通信之无名管道及其基础实验...

    管道简介 管道是Linux中进程间通信的一种方式,它把一个程序的输出直接连接到另一个程序的输入(其实我更愿意将管道比喻为农村浇地的管子).Linux的管道主要包括两种:无名管道和有名管道.这一节主要讲 ...

  6. 【嵌入式总复习】Linux管道详解——管道通信、无名管道、有名管道、具体应用示例

    目录 管道 1. 管道通信 1.1 通信模式 1.2 管道通信中特殊的名词 2. 无名管道(PIPE) 2.1 无名管道的通信原理 2.2 无名管道特点 2.3 如何操作无名管道 示例1 示例2 3. ...

  7. linux进程通信1:进程通信概述,管道通信原理(无名管道,有名管道),管道编程实战

    进程通信概述,管道通信原理(无名管道,有名管道),管道编程实战 1.进程间通信概述: 举例1: 你手机微信和别人手机微信通信 举例2: 如:父子进程wait 和 exit之间的通信 进程间通信(IPC ...

  8. 【学习笔记5】管道通信:命名管道

    目录 一.前言 二.基本概念 三.命名管道的创建和使用 3.1 函数原型 3.1.1 CreateNamedPipe 3.1.2 ConnectNamedPipe 3.1.3 WaitNamedPip ...

  9. 单工通信/半双工通信/全双工通信,串行传输/并行传输,同步传输/异步传输的区别

    学习通信的时候,这几个名词单工通信/半双工通信/全双工通信,串行传输/并行传输,同步传输/异步传输我一直都很迷,现在我总结一下,也是加深我的记忆了 1.按照信息在信道中的传输方向分为: a.单工通信: ...

  10. 计算机实际应用的例子,作业二:单工通信;半双工通信; 双工通信;有哪些实际应用的例子...

    单工通信: 所谓单工通信,是指消息只能单方向传输的工作方式.例如遥控.遥测,就是单工通信方式 单工通信信道是单向信道,发送端和接收端的身份是固定的,发送端只能发送信息,不能接收信息:接收端只能接收信息 ...

最新文章

  1. 电脑开机进入不了XP界面
  2. fprintf与fwrite的区别
  3. 【c基础】之 文件及其操作
  4. mysql 严格模式查看,如何查找和禁用MySQL严格模式?
  5. 关于C/C++中函数参数传递的规则
  6. cocos2dx中使用iconv转码(win32,iOS,Android)
  7. MFC中属性表单和向导对话框的使用
  8. c语言公路竖曲线要素代码,竖曲线要素
  9. Hbase与Hadoop版本对应
  10. html中如何在数字上加方框,EXCEL单元格中方框添加数字(或者数字添加方框)
  11. 机器人瓦力漫威_章节目录 86、机器人瓦力
  12. 数据分析真题日刷 | 网易2018校园招聘数据分析工程师笔试卷
  13. 当代女性修身养性的箴言书——《读史做女人》
  14. 工商名人堂 爱德华·约翰逊二世---富达基金的崛起(转载自新浪)
  15. distill介绍及优秀博客记录
  16. 【SQLite3+Qt开发】SQLite3简要介绍+在Qt5中的使用步骤
  17. phpcms 添加顶踩功能
  18. 火箭军下连学计算机专业好吗,火箭军招收定向培养士官院校增至16所 涵盖18个专业...
  19. 实训计算机硬盘分区的心得体会,计算机实训报告
  20. 三天时间, 无线破解从入门到放弃

热门文章

  1. java程序员培训班要多少钱,一招彻底弄懂!
  2. 12.qgis二次开发qt中实现图层树右键图层更改图层颜色,以及图层标注。
  3. AES简介加密算法介绍
  4. MIT人工智能实验室:如何做研究
  5. Safe Browsing API
  6. 震惊!没想到你居然是这样的for循环(UC打钱!)
  7. BH1750 传感器实战教学 —— 硬件设计篇
  8. 移动端手机 摇一摇加声音
  9. 地球子午圈和卯酉圈曲率半径计算公式
  10. 华硕无线路由打印机服务器,彻底了解WL-500g型的华硕无线网络路由器