Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
R
RoboPLC
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
黄新宇
RoboPLC
Commits
9eb698c1
提交
9eb698c1
authored
3月 05, 2024
作者:
Serhij S
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
docs
上级
56944e5b
隐藏空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
102 行增加
和
48 行删除
+102
-48
README.md
README.md
+54
-0
hub.rs
src/hub.rs
+15
-15
lib.rs
src/lib.rs
+1
-1
pchannel.rs
src/pchannel.rs
+26
-26
pdeque.rs
src/pdeque.rs
+6
-6
没有找到文件。
README.md
浏览文件 @
9eb698c1
...
...
@@ -25,3 +25,57 @@ width="350" />
*
thread-safe out-of-the-box
*
frames may be forcibly pushed, overriding the previous ones, like in a ring-buffer.
## Hub
[
`hub::Hub`
]
implements a data-hub (in process pub/sub) model, when multiple
clients (usually thread workers) exchange data via a single virtual bus instead
of using direct channels.
This brings some additional overhead into data exchange, however makes the
architecture significantly clearer, lowers code support costs and brings
additional features.
<img
src="https://raw.githubusercontent.com/eva-ics/roboplc/main/schemas/hub.png"
width="550" />
*
classic pub/sub patterns with no data serialization overhead
*
based on
[
`pchannel`
]
which allows to mix different kinds of data and apply
additional policies if required
*
a fully passive model with no "server" thread.
## pdeque and pchannel
A policy-based deque
[
`pdeque::Deque`
]
is a component to build policy-based
channels.
[
`pchannel`
]
is a channel module, based on the policy-based deque.
Data policies supported:
*
**Always**
a frame is always delivered
*
**Optional**
a frame can be skipped if no room
*
**Single**
a frame must be delivered only once (the latest one)
*
**SingleOptional**
a frame must be delivered only once (the latest one) and
is optional
Additionally, components support ordering by data priority and automatically
drop expired data if the data type has got an expiration marker method
implemented.
Without policies applied, speed is similar to other popular channel/storage
implementations. With policies data transfer speed can be lower, latency can
rise, however the overall effect is significantly better as the data is
processed directly inside a channel or a storage buffer.
## Real-time
[
`thread_rt::Builder`
]
provides a thread builder component, which extends the
standard thread builder with real-time capabilities: scheduler policies and CPU
affinity (Linux only).
[
`supervisor::Supervisor`
]
provides a lightweight task supervisor to manage
launched threads.
src/hub.rs
浏览文件 @
9eb698c1
...
...
@@ -3,7 +3,7 @@ use std::sync::Arc;
use
parking_lot
::
Mutex
;
use
crate
::
pchannel
::{
self
,
Receiver
};
use
crate
::{
pchannel
::
Sender
,
Message
DeliveryPolicy
};
use
crate
::{
pchannel
::
Sender
,
Data
DeliveryPolicy
};
use
crate
::{
Error
,
Result
};
type
ConditionFunction
<
T
>
=
Box
<
dyn
Fn
(
&
T
)
->
bool
+
Send
+
Sync
>
;
...
...
@@ -13,11 +13,11 @@ pub const DEFAULT_PRIORITY: usize = 100;
pub
const
DEFAULT_CHANNEL_CAPACITY
:
usize
=
1024
;
/// Data communcation hub to implement in-process pub/sub model for thread workers
pub
struct
Hub
<
T
:
Message
DeliveryPolicy
+
Clone
>
{
pub
struct
Hub
<
T
:
Data
DeliveryPolicy
+
Clone
>
{
inner
:
Arc
<
Mutex
<
HubInner
<
T
>>>
,
}
impl
<
T
:
Message
DeliveryPolicy
+
Clone
>
Clone
for
Hub
<
T
>
{
impl
<
T
:
Data
DeliveryPolicy
+
Clone
>
Clone
for
Hub
<
T
>
{
fn
clone
(
&
self
)
->
Self
{
Self
{
inner
:
self
.inner
.clone
(),
...
...
@@ -25,7 +25,7 @@ impl<T: MessageDeliveryPolicy + Clone> Clone for Hub<T> {
}
}
impl
<
T
:
Message
DeliveryPolicy
+
Clone
>
Default
for
Hub
<
T
>
{
impl
<
T
:
Data
DeliveryPolicy
+
Clone
>
Default
for
Hub
<
T
>
{
fn
default
()
->
Self
{
Self
{
inner
:
<
_
>
::
default
(),
...
...
@@ -33,7 +33,7 @@ impl<T: MessageDeliveryPolicy + Clone> Default for Hub<T> {
}
}
impl
<
T
:
Message
DeliveryPolicy
+
Clone
>
Hub
<
T
>
{
impl
<
T
:
Data
DeliveryPolicy
+
Clone
>
Hub
<
T
>
{
pub
fn
new
()
->
Self
{
Self
::
default
()
}
...
...
@@ -173,14 +173,14 @@ impl<T: MessageDeliveryPolicy + Clone> Hub<T> {
}
}
struct
HubInner
<
T
:
Message
DeliveryPolicy
+
Clone
>
{
struct
HubInner
<
T
:
Data
DeliveryPolicy
+
Clone
>
{
default_channel_capacity
:
usize
,
subscriptions
:
Vec
<
Arc
<
Subscription
<
T
>>>
,
}
impl
<
T
>
Default
for
HubInner
<
T
>
where
T
:
Message
DeliveryPolicy
+
Clone
,
T
:
Data
DeliveryPolicy
+
Clone
,
{
fn
default
()
->
Self
{
Self
{
...
...
@@ -190,13 +190,13 @@ where
}
}
pub
struct
Client
<
T
:
Message
DeliveryPolicy
+
Clone
>
{
pub
struct
Client
<
T
:
Data
DeliveryPolicy
+
Clone
>
{
name
:
Arc
<
str
>
,
hub
:
Hub
<
T
>
,
rx
:
Receiver
<
T
>
,
}
impl
<
T
:
Message
DeliveryPolicy
+
Clone
>
Client
<
T
>
{
impl
<
T
:
Data
DeliveryPolicy
+
Clone
>
Client
<
T
>
{
/// Sends a message to hub-subscribed clients, ignores send errors
pub
fn
send
(
&
self
,
message
:
T
)
{
self
.hub
.send
(
message
);
...
...
@@ -221,13 +221,13 @@ impl<T: MessageDeliveryPolicy + Clone> Client<T> {
}
}
impl
<
T
:
Message
DeliveryPolicy
+
Clone
>
Drop
for
Client
<
T
>
{
impl
<
T
:
Data
DeliveryPolicy
+
Clone
>
Drop
for
Client
<
T
>
{
fn
drop
(
&
mut
self
)
{
self
.hub
.unregister
(
&
self
.name
);
}
}
pub
struct
ClientOptions
<
T
:
Message
DeliveryPolicy
+
Clone
>
{
pub
struct
ClientOptions
<
T
:
Data
DeliveryPolicy
+
Clone
>
{
name
:
Arc
<
str
>
,
priority
:
usize
,
capacity
:
Option
<
usize
>
,
...
...
@@ -235,7 +235,7 @@ pub struct ClientOptions<T: MessageDeliveryPolicy + Clone> {
condition
:
ConditionFunction
<
T
>
,
}
impl
<
T
:
Message
DeliveryPolicy
+
Clone
>
ClientOptions
<
T
>
{
impl
<
T
:
Data
DeliveryPolicy
+
Clone
>
ClientOptions
<
T
>
{
pub
fn
new
<
F
>
(
name
:
&
str
,
condition
:
F
)
->
Self
where
F
:
Fn
(
&
T
)
->
bool
+
Send
+
Sync
+
'static
,
...
...
@@ -295,7 +295,7 @@ macro_rules! event_matches {
};
}
struct
Subscription
<
T
:
Message
DeliveryPolicy
+
Clone
>
{
struct
Subscription
<
T
:
Data
DeliveryPolicy
+
Clone
>
{
name
:
Arc
<
str
>
,
tx
:
Sender
<
T
>
,
priority
:
usize
,
...
...
@@ -304,7 +304,7 @@ struct Subscription<T: MessageDeliveryPolicy + Clone> {
#[cfg(test)]
mod
test
{
use
crate
::{
event_matches
,
Message
DeliveryPolicy
};
use
crate
::{
event_matches
,
Data
DeliveryPolicy
};
use
super
::
Hub
;
...
...
@@ -315,7 +315,7 @@ mod test {
Test
,
}
impl
Message
DeliveryPolicy
for
Message
{}
impl
Data
DeliveryPolicy
for
Message
{}
#[test]
fn
test_hub
()
{
...
...
src/lib.rs
浏览文件 @
9eb698c1
...
...
@@ -92,7 +92,7 @@ pub enum DeliveryPolicy {
}
/// Implements delivery policies for own data types
pub
trait
Message
DeliveryPolicy
pub
trait
Data
DeliveryPolicy
where
Self
:
Sized
,
{
...
...
src/pchannel.rs
浏览文件 @
9eb698c1
use
std
::
sync
::
Arc
;
use
crate
::{
pdeque
::
Deque
,
Error
,
Message
DeliveryPolicy
,
Result
};
use
crate
::{
pdeque
::
Deque
,
Error
,
Data
DeliveryPolicy
,
Result
};
use
object_id
::
UniqueId
;
use
parking_lot
::{
Condvar
,
Mutex
};
struct
Channel
<
T
:
Message
DeliveryPolicy
>
(
Arc
<
ChannelInner
<
T
>>
);
struct
Channel
<
T
:
Data
DeliveryPolicy
>
(
Arc
<
ChannelInner
<
T
>>
);
impl
<
T
:
Message
DeliveryPolicy
>
Channel
<
T
>
{
impl
<
T
:
Data
DeliveryPolicy
>
Channel
<
T
>
{
fn
id
(
&
self
)
->
usize
{
self
.
0
.id
.as_usize
()
}
}
impl
<
T
:
Message
DeliveryPolicy
>
Eq
for
Channel
<
T
>
{}
impl
<
T
:
Data
DeliveryPolicy
>
Eq
for
Channel
<
T
>
{}
impl
<
T
:
Message
DeliveryPolicy
>
PartialEq
for
Channel
<
T
>
{
impl
<
T
:
Data
DeliveryPolicy
>
PartialEq
for
Channel
<
T
>
{
fn
eq
(
&
self
,
other
:
&
Self
)
->
bool
{
self
.id
()
==
other
.id
()
}
...
...
@@ -22,20 +22,20 @@ impl<T: MessageDeliveryPolicy> PartialEq for Channel<T> {
impl
<
T
>
Clone
for
Channel
<
T
>
where
T
:
Message
DeliveryPolicy
,
T
:
Data
DeliveryPolicy
,
{
fn
clone
(
&
self
)
->
Self
{
Self
(
self
.
0
.clone
())
}
}
struct
ChannelInner
<
T
:
Message
DeliveryPolicy
>
{
struct
ChannelInner
<
T
:
Data
DeliveryPolicy
>
{
id
:
UniqueId
,
pc
:
Mutex
<
PolicyChannel
<
T
>>
,
available
:
Condvar
,
}
impl
<
T
:
Message
DeliveryPolicy
>
ChannelInner
<
T
>
{
impl
<
T
:
Data
DeliveryPolicy
>
ChannelInner
<
T
>
{
fn
try_send
(
&
self
,
value
:
T
)
->
Result
<
()
>
{
let
mut
pc
=
self
.pc
.lock
();
if
pc
.receivers
==
0
{
...
...
@@ -98,7 +98,7 @@ impl<T: MessageDeliveryPolicy> ChannelInner<T> {
}
}
impl
<
T
:
Message
DeliveryPolicy
>
Channel
<
T
>
{
impl
<
T
:
Data
DeliveryPolicy
>
Channel
<
T
>
{
fn
new
(
capacity
:
usize
,
ordering
:
bool
)
->
Self
{
Self
(
ChannelInner
{
...
...
@@ -111,7 +111,7 @@ impl<T: MessageDeliveryPolicy> Channel<T> {
}
}
struct
PolicyChannel
<
T
:
Message
DeliveryPolicy
>
{
struct
PolicyChannel
<
T
:
Data
DeliveryPolicy
>
{
queue
:
Deque
<
T
>
,
senders
:
usize
,
receivers
:
usize
,
...
...
@@ -119,7 +119,7 @@ struct PolicyChannel<T: MessageDeliveryPolicy> {
impl
<
T
>
PolicyChannel
<
T
>
where
T
:
Message
DeliveryPolicy
,
T
:
Data
DeliveryPolicy
,
{
fn
new
(
capacity
:
usize
,
ordering
:
bool
)
->
Self
{
assert
!
(
capacity
>
0
,
"channel capacity MUST be > 0"
);
...
...
@@ -134,14 +134,14 @@ where
#[derive(Eq,
PartialEq)]
pub
struct
Sender
<
T
>
where
T
:
Message
DeliveryPolicy
,
T
:
Data
DeliveryPolicy
,
{
channel
:
Channel
<
T
>
,
}
impl
<
T
>
Sender
<
T
>
where
T
:
Message
DeliveryPolicy
,
T
:
Data
DeliveryPolicy
,
{
#[inline]
pub
fn
send
(
&
self
,
value
:
T
)
->
Result
<
()
>
{
...
...
@@ -171,7 +171,7 @@ where
impl
<
T
>
Clone
for
Sender
<
T
>
where
T
:
Message
DeliveryPolicy
,
T
:
Data
DeliveryPolicy
,
{
fn
clone
(
&
self
)
->
Self
{
self
.channel
.
0
.pc
.lock
()
.senders
+=
1
;
...
...
@@ -183,7 +183,7 @@ where
impl
<
T
>
Drop
for
Sender
<
T
>
where
T
:
Message
DeliveryPolicy
,
T
:
Data
DeliveryPolicy
,
{
fn
drop
(
&
mut
self
)
{
self
.channel
.
0
.pc
.lock
()
.senders
-
=
1
;
...
...
@@ -194,14 +194,14 @@ where
#[derive(Eq,
PartialEq)]
pub
struct
Receiver
<
T
>
where
T
:
Message
DeliveryPolicy
,
T
:
Data
DeliveryPolicy
,
{
channel
:
Channel
<
T
>
,
}
impl
<
T
>
Receiver
<
T
>
where
T
:
Message
DeliveryPolicy
,
T
:
Data
DeliveryPolicy
,
{
#[inline]
pub
fn
recv
(
&
self
)
->
Result
<
T
>
{
...
...
@@ -231,7 +231,7 @@ where
impl
<
T
>
Clone
for
Receiver
<
T
>
where
T
:
Message
DeliveryPolicy
,
T
:
Data
DeliveryPolicy
,
{
fn
clone
(
&
self
)
->
Self
{
self
.channel
.
0
.pc
.lock
()
.receivers
+=
1
;
...
...
@@ -243,7 +243,7 @@ where
impl
<
T
>
Drop
for
Receiver
<
T
>
where
T
:
Message
DeliveryPolicy
,
T
:
Data
DeliveryPolicy
,
{
fn
drop
(
&
mut
self
)
{
self
.channel
.
0
.pc
.lock
()
.receivers
-
=
1
;
...
...
@@ -251,7 +251,7 @@ where
}
}
fn
make_channel
<
T
:
Message
DeliveryPolicy
>
(
ch
:
Channel
<
T
>
)
->
(
Sender
<
T
>
,
Receiver
<
T
>
)
{
fn
make_channel
<
T
:
Data
DeliveryPolicy
>
(
ch
:
Channel
<
T
>
)
->
(
Sender
<
T
>
,
Receiver
<
T
>
)
{
let
tx
=
Sender
{
channel
:
ch
.clone
(),
};
...
...
@@ -259,24 +259,24 @@ fn make_channel<T: MessageDeliveryPolicy>(ch: Channel<T>) -> (Sender<T>, Receive
(
tx
,
rx
)
}
/// Creates a bounded channel which respects [`
Message
DeliveryPolicy`] rules with no message
/// Creates a bounded channel which respects [`
Data
DeliveryPolicy`] rules with no message
/// priority ordering
///
/// # Panics
///
/// Will panic if the capacity is zero
pub
fn
bounded
<
T
:
Message
DeliveryPolicy
>
(
capacity
:
usize
)
->
(
Sender
<
T
>
,
Receiver
<
T
>
)
{
pub
fn
bounded
<
T
:
Data
DeliveryPolicy
>
(
capacity
:
usize
)
->
(
Sender
<
T
>
,
Receiver
<
T
>
)
{
let
ch
=
Channel
::
new
(
capacity
,
false
);
make_channel
(
ch
)
}
/// Creates a bounded channel which respects [`
Message
DeliveryPolicy`] rules and has got message
/// Creates a bounded channel which respects [`
Data
DeliveryPolicy`] rules and has got message
/// priority ordering turned on
///
/// # Panics
///
/// Will panic if the capacity is zero
pub
fn
ordered
<
T
:
Message
DeliveryPolicy
>
(
capacity
:
usize
)
->
(
Sender
<
T
>
,
Receiver
<
T
>
)
{
pub
fn
ordered
<
T
:
Data
DeliveryPolicy
>
(
capacity
:
usize
)
->
(
Sender
<
T
>
,
Receiver
<
T
>
)
{
let
ch
=
Channel
::
new
(
capacity
,
true
);
make_channel
(
ch
)
}
...
...
@@ -285,7 +285,7 @@ pub fn ordered<T: MessageDeliveryPolicy>(capacity: usize) -> (Sender<T>, Receive
mod
test
{
use
std
::{
thread
,
time
::
Duration
};
use
crate
::{
DeliveryPolicy
,
Message
DeliveryPolicy
};
use
crate
::{
DeliveryPolicy
,
Data
DeliveryPolicy
};
use
super
::
bounded
;
...
...
@@ -296,7 +296,7 @@ mod test {
Spam
,
}
impl
Message
DeliveryPolicy
for
Message
{
impl
Data
DeliveryPolicy
for
Message
{
fn
delivery_policy
(
&
self
)
->
DeliveryPolicy
{
match
self
{
Message
::
Test
(
_
)
=>
DeliveryPolicy
::
Always
,
...
...
src/pdeque.rs
浏览文件 @
9eb698c1
use
std
::
collections
::
VecDeque
;
use
crate
::{
DeliveryPolicy
,
Message
DeliveryPolicy
};
use
crate
::{
DeliveryPolicy
,
Data
DeliveryPolicy
};
/// A deque which stores values with respect of [`
Message
DeliveryPolicy`]
/// A deque which stores values with respect of [`
Data
DeliveryPolicy`]
#[derive(Clone,
Debug)]
pub
struct
Deque
<
T
>
where
T
:
Message
DeliveryPolicy
,
T
:
Data
DeliveryPolicy
,
{
data
:
VecDeque
<
T
>
,
capacity
:
usize
,
...
...
@@ -23,7 +23,7 @@ pub struct TryPushOutput<T> {
impl
<
T
>
Deque
<
T
>
where
T
:
Message
DeliveryPolicy
,
T
:
Data
DeliveryPolicy
,
{
/// Creates a new bounded deque
#[inline]
...
...
@@ -42,7 +42,7 @@ where
}
/// Tries to store the value
///
/// Returns the value back if there is no capacity even after all [`
Message
DeliveryPolicy`]
/// Returns the value back if there is no capacity even after all [`
Data
DeliveryPolicy`]
/// rules have been applied
pub
fn
try_push
(
&
mut
self
,
value
:
T
)
->
TryPushOutput
<
T
>
{
macro_rules!
push
{
...
...
@@ -126,7 +126,7 @@ where
}
}
fn
sort_by_priority
<
T
:
Message
DeliveryPolicy
>
(
v
:
&
mut
VecDeque
<
T
>
)
{
fn
sort_by_priority
<
T
:
Data
DeliveryPolicy
>
(
v
:
&
mut
VecDeque
<
T
>
)
{
v
.rotate_right
(
v
.as_slices
()
.
1
.len
());
assert
!
(
v
.as_slices
()
.
1
.is_empty
());
v
.as_mut_slices
()
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论