- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我最近开始用 rust 编码,我很喜欢它。我在一个要“包装” C-API的项目上编码。在一种情况下,我必须在Rust中定义C可以调用的回调。我让bindgen创建了回调。由于代码需要异步运行,因此我使用了tokio。
我想要达成的目标
我将主要功能创建为tokio::main。在主要功能中,我创建了2个异步任务,一个监听 channel ,另一个监听C-API中的消息队列。如果消息可用,我想通过回调函数上的 channel 发送消息,这样我就可以在任务中接收消息,而我正在监听事件。稍后,我想通过SSE或GraphQL订阅将这些消息发送给多个客户端。
我无法更改C回调,因为它们需要可传递到C-API,并且必须使用回调,否则我不会收到消息。
我的最新方法看起来像这样简化:
use lazy_static::lazy_static;
use tokio::sync::{
mpsc::{channel, Receiver, Sender},
Mutex,
};
use bindgen::{notify_connect, notify_connectionstate};
lazy_static! {
static ref BROADCAST_CONNECT: Mutex<(Sender<bool>, Receiver<bool>)> = Mutex::new(channel(128));
static ref BROADCAST_CONNECTIONSTATE: Mutex<(Sender<u32>, Receiver<u32>)> = Mutex::new(channel(128));
}
#[tokio::main]
async fn main() {
unsafe { notify_connect(Some(_notify_connect)) } // pass the callback function to the C-API
unsafe { notify_connectionstate(Some(_notify_connectionstate)) } // pass the callback function to the C-API
tokio::spawn(async move { // wait for a channel to have a message
loop {
tokio::select! {
// wating for a channel to receive a message
Some(msg) = BROADCAST_CONNECT.lock().await.1.recv() => println!("{}", msg),
Some(msg) = BROADCAST_CONNECTIONSTATE.lock().await.1.recv() => println!("{}", msg),
}
}
});
let handle2 = tokio::spawn(async move {
loop {
unsafe {
message_queue_in_c(
some_handle,
true,
Duration::milliseconds(100).num_microseconds().unwrap(),
)
}
}
});
handle.await.unwrap();
habdle2.await.unwrap();
}
// the callback function that gets called from the C-API
unsafe extern "C" fn _notify_connect(is_connected: bool) {
// C-API is not async, so use synchronous lock
match BROADCAST_CONNECT.try_lock() {
Ok(value) => match value.0.blocking_send(is_connected) {
Ok(_) => {}
Err(e) => {
eprintln!("{}", e)
}
},
Err(e) => {
eprintln!("{}", e)
}
}
}
unsafe extern "C" fn _notify_connectionstate(connectionstate: u32) {
match BROADCAST_CONNECTIONSTATE.try_lock() {
Ok(value) => match value.0.blocking_send(connectionstate) {
Ok(_) => {}
Err(e) => {
eprintln!("{}", e)
}
},
Err(e) => {
eprintln!("{}", e)
}
}
}
问题:
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:37:29
|
35 | / tokio::select! {
36 | | Some(msg) = BROADCAST_CONNECT.lock().await.1.recv() => println!("{}", msg),
37 | | Some(msg) = BROADCAST_CONNECTIONSTATE.lock().await.1.recv() => println!("{}", msg),
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
38 | | }
| | -
| | |
| |_____________temporary value is freed at the end of this statement
| borrow later captured here by closure
|
= note: consider using a `let` binding to create a longer lived value
我了解该消息以及发生这种情况的原因,但是我想不出解决方案。
use lazy_static::lazy_static;
use crossbeam::{
channel::{bounded, Receiver, Sender},
select,
};
use bindgen::{notify_connect, notify_connectionstate};
lazy_static! {
static ref BROADCAST_CONNECT: (Sender<bool>, Receiver<bool>) = bounded(128);
static ref BROADCAST_CONNECTIONSTATE: (Sender<u32>, Receiver<u32>) = bounded(128);
}
#[tokio::main]
async fn main() {
unsafe { notify_connect(Some(_notify_connect)) } // pass the callback function to the C-API
unsafe { notify_connectionstate(Some(_notify_connectionstate)) } // pass the callback function to the C-API
let handle1 = tokio::spawn(async move {
loop {
select! {
recv(&BROADCAST_CONNECT.1) -> msg => println!("is_connected: {:?}", msg.unwrap()),
recv(&BROADCAST_CONNECTIONSTATE.1) -> msg => println!("connectionstate: {:?}", msg.unwrap()),
}
}
});
let handle2 = tokio::spawn(async move {
loop {
unsafe {
message_queue_in_c(
some_handle,
true,
Duration::milliseconds(100).num_microseconds().unwrap(),
)
}
}
});
handle.await.unwrap();
handle2.await.unwrap();
}
// the callback function thats gets called from the C-API
unsafe extern "C" fn _notify_connect(is_connected: bool) {
match &BROADCAST_CONNECT.0.send(is_connected) {
Ok(_) => {}
Err(e) => eprintln!("{}", e),
};
}
unsafe extern "C" fn _notify_connectionstate(connectionstate: u32) {
match BROADCAST_CONNECTIONSTATE.0.send(connectionstate) {
Ok(_) => {}
Err(e) => eprintln!("{}", e),
}
}
选择
use tokio::sync::{
mpsc::{channel, Receiver, Sender},
Mutex,
};
use bindgen::{notify_connect, notify_connectionstate};
#[tokio::main]
async fn main() {
let app = app::App::new();
let mut broadcast_connect = channel::<bool>(128);
let mut broadcast_connectionstate = channel::<bool>(128);
let notify_connect = {
unsafe extern "C" fn _notify_connect(is_connected: bool) {
match broadcast_connect.0.blocking_send(is_connected) {
Ok(_) => {}
Err(e) => {
eprintln!("{}", e)
}
}
}
};
let notify_connectionstate = {
unsafe extern "C" fn _notify_connectionstate(connectionstate: u32) {
match broadcast_connectionstate.0.blocking_send(connectionstate) {
Ok(_) => {}
Err(e) => {
eprintln!("{}", e)
}
}
}
};
unsafe { notify_connect(Some(notify_connect)) } // pass the callback function to the C-API
unsafe { notify_connectionstate(Some(notify_connectionstate)) } // pass the callback function to the C-API
let handle = tokio::spawn(async move {
loop {
tokio::select! {
Some(msg) = broadcast_connect.1.recv() => println!("{}", msg),
Some(msg) = broadcast_connectionstate.1.recv() => println!("{}", msg),
}
}
});
let handle2 = tokio::spawn(async move {
loop {
unsafe {
message_queue_in_c(
some_handle,
true,
Duration::milliseconds(100).num_microseconds().unwrap(),
)
}
}
});
handle.await.unwrap();
handle2.await.unwrap();
}
这种方法的问题
can't capture dynamic environment in a fn item
--> src/main.rs:47:19
|
47 | match broadcast_connectionstate.0.blocking_send(connectionstate) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: use the `|| { ... }` closure form instead
如果有人可以解决我的任何一个问题,那就太好了。如果这是一种全新的方法,那也可以。如果没有 channel ,tokio或其他方法,那也没关系。我主要是使用tokio的,因为我也使用了tokio的 crate ,因此我不必再有更多依赖项。
最佳答案
如果您对第一个示例进行了以下更改,则它应该可以工作:
tokio::sync::Mutex
替换std::sync::Mutex
,因此您不必在回调中使用try_lock
。 std::thread::spawn
而不是tokio::spawn
在专用线程上运行阻塞的C代码。 (why?)static ref BROADCAST_CONNECT: Mutex<Option<Sender<bool>>> = Mutex::new(None);
// in main
let (send, recv) = channel(128);
*BROADCAST_CONNECT.lock().unwrap() = Some(send);
如果要使用有界 channel ,可以先克隆 channel ,然后在该锁上调用
drop
,然后使用
blocking_send
来释放该锁。对于无限制的 channel ,这无关紧要,因为发送是即时的。
// in C callback
let lock = BROADCAST_CONNECT.lock().unwrap();
let send = lock.as_ref().clone();
drop(lock);
send.blocking_send(...);
关于asynchronous - rust lazy_static和tokio::select中的tokio::sync::mpsc::channel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65452692/
当运行这样的代码时: use futures::executor; ... pub fn store_temporary_password(email: &str, password: &str) -
我遵循了mdns Rust文档并粘贴了示例代码,但它抛出了以下错误:。以下是我拥有的代码:。依赖关系:。我遗漏了什么?我试着在网上寻找,但没有找到如何为这个用例创建一个反应堆。
假设我想与 Tokio 同时下载两个网页... 要么我可以用 tokio::spawn() 来实现这个: async fn v1() { let t1 = tokio::spawn(reqwe
我制作了一个还能显示天气的 LED 时钟。我的程序在一个循环中做了几件不同的事情,每件事都有不同的间隔: 每 50 毫秒更新一次 LED, 每 1 秒检查一次光照水平(以调整亮度), 每 10 分钟获
我制作了一个还能显示天气的 LED 时钟。我的程序在一个循环中做了几件不同的事情,每件事都有不同的间隔: 每 50 毫秒更新一次 LED, 每 1 秒检查一次光照水平(以调整亮度), 每 10 分钟获
tokio::run_async + futures 0.3 + tokio::net::UnixStream panic 。 设置 [package] name = "prac" version =
在我的 rust 项目中,cargo 提示使用 tokio::sync 时使用的类型不在范围内: use tokio::sync::RwLock; | ^^^^^ use of undec
我将如何使用自定义 tokio 运行时构建器并且没有主宏来实现这个 tokio_postgres 示例? 这工作正常,根据 tokio_postgres docs : 示例/withmacro.rs
目前我有一个主要的写成 async example for the Reqwest library . #[tokio::main] async fn main() -> Result> { 我们可以
我遵循the mdns Rust documentation并粘贴了示例代码,但它引发以下错误: thread 'main' panicked at 'there is no reactor runn
extern crate tokio; // 0.1.22 use tokio::io; use tokio::net::TcpListener; use tokio::prelude::*; use
我正在尝试使用 tokio 编写一个测试程序,该程序从网站获取文件并将流式响应写入文件。 hyper 网站显示了一个使用 while 循环并使用 .data() 的示例。方法响应主体,但我想用 .ma
我在 prod 中运行一个 rust Tokio 应用程序。在上一个版本中,我有一个错误,一些请求导致我的代码进入无限循环。 发生的事情是当进入无限循环的任务卡住时,所有其他任务继续正常工作并处理请求
下面的程序应该从多个线程定期打印,但是 tokio::time::sleep没有按我预期的那样工作: use tokio::prelude::*; //0.3.4 use tokio::runtime
我使用如下代码启动 Tokio 运行时: tokio::run(my_future); 我的 future 继续启动一堆任务以响应各种条件。 其中一项任务负责确定程序何时关闭。但是,我不知道如何让该任
我正在尝试构建一个可以管理来自 websocket 的提要但能够在多个提要之间切换的对象。 有一个 Feed 特征: trait Feed { async fn start(&mut self
我有一个设置,我的程序使用 std::thread::spawn 为 CPU 绑定(bind)计算生成多个线程。 我需要一个 GRPC 服务器来处理传入的命令并流式传输工作线程完成的输出。我正在为 G
我做计算机系统项目的第一个经历是使用 vanilla Java 构建服务器,然后在 Android 手机上构建客户端。从那时起,我发现有很多框架可以帮助管理可伸缩性并消除编写样板代码的需要。 我正在尝
我将从 Delphi XE4 迁移到 10.2。新的单位名称样式(深灰色背景上的黑色文本)不适合我的视力。有人可以建议如何更改它,最好不使用第 3 方加载项吗? 这就是新样式的样子,我很难阅读事件单位
我一直在寻找tokio源代码来获取问题的答案,并且给人以the sleep method literally puts a timer with duration的印象,但是我认为我可能误解了代码,因
我是一名优秀的程序员,十分优秀!