防止 Fn 在已经 运行 时再次被调用
Preventing a Fn from being invoked again while it's already running
我正在使用 inputbot 编写一个程序,为我的计算机提供一些全局宏。例如,当我按下 h 键时,它应该执行宏输入
Hello World
进入当前应用程序。我试着这样实现它:
extern crate inputbot;
fn main() {
let mut callback = || {
inputbot::KeySequence("Hello World").send();
};
inputbot::KeybdKey::HKey.bind(callback);
inputbot::handle_input_events();
}
然而,当我按下 h 键时,我实际得到的是:
hHHHHHHHHHHHHHHHHHHHHHHHHHEHEHhEhEEHHhEhEhEHhEHHEHHEEHhEHlhEHEHHEHLEHLHeeleleelelelllelelleelehlhehlleeheehelheelleeleelhllllllellelolelellelleoleloloelellololol olollollelllolllol lloo ol o oo l lo lolooloooloo loo LOWOLO O L OLW WOWO L WLLOLOW L O O O O o WOWW low o oOow WWW WOW wowooWWWO oOWRWOoor W RoW oOWorororWRRWLR rLROwoRWLWOworo WorrrRWl ow o WRLR OLw o OWLDol rollWWLDWowDLlroWWo r oWDWOL dorRrwrolrdrrorlrLWDRdodRLowdllrllolrdlrddolrdlrldowldorowlrdlrorloLDLWDLoddlrddlrdldldldrrdordldrlrddrodlrrldoldlrlddldlrdlldlrdlddrlddldddlddlddd
每次发送 h 键事件时,宏都会触发自身。
如何防止 Fn
在另一个实例仍然是 运行 时被再次调用? 这是一个小程序的主要功能应用程序,所以没有什么比真正担心兼容性的了。
我天真的尝试修复
这是在 main
中添加一个 mut running
变量,当它是 运行 或 immediately
[=56] 时 callback
将设置为 true
=] 如果已经为真:
extern crate inputbot;
use std::time::Duration;
use std::thread::sleep;
fn main() {
let mut running = false;
let mut callback = || {
if running { return };
running = true;
inputbot::KeySequence("Hello World").send();
// wait to make sure keyboard events are done.
sleep(Duration::from_millis(125));
running = false;
};
inputbot::KeybdKey::HKey.bind(callback);
inputbot::handle_input_events();
}
但是,这无法编译:
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
经过一些阅读,我现在的理解是 Fn
闭包(inputbot 的 .bind()
方法需要)不能拥有任何可变数据,例如捕获的 mut
变量。
也许可以将变量包装在某种非 mut
值中?也许某种锁,使潜在的并发安全,就像这个 pseudocde?
fn main() {
let mut running = false;
let lockedRunning = example::Lock(&running);
let mut callback = || {
{
let mut running = lockedRunning.acquire();
if running { return };
running = true;
}
inputbot::KeySequence("Hello World").send();
// wait to make sure keyboard events are done.
sleep(Duration::from_millis(125));
{
let mut running = lockedRunning.acquire();
running = false;
}
};
}
这里你要的是函数本身是互斥的
Rust 允许您使用 Mutex
结构来执行此操作。它允许您持有一把锁,当获得该锁时,其他任何人都无法使用它,直到您释放它。
具体来说,您想要的功能是 try_lock
方法,该方法允许您检查是否已获取锁并允许您处理这种情况。
let lock = mutex.try_lock();
match lock {
Ok(_) => {
// We are the sole owners here
}
Err(TryLockError::WouldBlock) => return,
Err(TryLockError::Poisoned(_)) => {
println!("The mutex is poisoned");
return
}
}
使用原子值比 Mutex
简单一点,因为您无需担心失败情况,并且无需使用 lazy-static 即可轻松将其制成静态变量:
use std::sync::atomic::{AtomicBool, Ordering};
fn main() {
let is_being_called = AtomicBool::new(false);
bind(move || {
if !is_being_called.compare_and_swap(false, true, Ordering::SeqCst) {
print!("I'm doing work");
is_being_called.store(false, Ordering::SeqCst);
}
});
}
我预感这也比使用 Mutex
更有效,因为不需要进行堆分配,但我没有对其进行基准测试。
如果您处于单线程上下文中并且您的回调以某种方式(意外地?)递归(which closures cannot be),您还可以使用 Cell
:
use std::cell::Cell;
fn main() {
let is_being_called = Cell::new(false);
bind(move || {
if !is_being_called.get() {
is_being_called.set(true);
print!("doing work");
is_being_called.set(false);
}
})
}
如果你碰巧有一个 FnMut
闭包,你甚至不需要 Cell
并且可以只使用布尔值:
fn main() {
let mut is_being_called = false;
bind(move || {
if !is_being_called {
is_being_called = true;
print!("doing work");
is_being_called = false;
}
})
}
我正在使用 inputbot 编写一个程序,为我的计算机提供一些全局宏。例如,当我按下 h 键时,它应该执行宏输入
Hello World
进入当前应用程序。我试着这样实现它:
extern crate inputbot;
fn main() {
let mut callback = || {
inputbot::KeySequence("Hello World").send();
};
inputbot::KeybdKey::HKey.bind(callback);
inputbot::handle_input_events();
}
然而,当我按下 h 键时,我实际得到的是:
hHHHHHHHHHHHHHHHHHHHHHHHHHEHEHhEhEEHHhEhEhEHhEHHEHHEEHhEHlhEHEHHEHLEHLHeeleleelelelllelelleelehlhehlleeheehelheelleeleelhllllllellelolelellelleoleloloelellololol olollollelllolllol lloo ol o oo l lo lolooloooloo loo LOWOLO O L OLW WOWO L WLLOLOW L O O O O o WOWW low o oOow WWW WOW wowooWWWO oOWRWOoor W RoW oOWorororWRRWLR rLROwoRWLWOworo WorrrRWl ow o WRLR OLw o OWLDol rollWWLDWowDLlroWWo r oWDWOL dorRrwrolrdrrorlrLWDRdodRLowdllrllolrdlrddolrdlrldowldorowlrdlrorloLDLWDLoddlrddlrdldldldrrdordldrlrddrodlrrldoldlrlddldlrdlldlrdlddrlddldddlddlddd
每次发送 h 键事件时,宏都会触发自身。
如何防止 Fn
在另一个实例仍然是 运行 时被再次调用? 这是一个小程序的主要功能应用程序,所以没有什么比真正担心兼容性的了。
我天真的尝试修复
这是在 main
中添加一个 mut running
变量,当它是 运行 或 immediately
[=56] 时 callback
将设置为 true
=] 如果已经为真:
extern crate inputbot;
use std::time::Duration;
use std::thread::sleep;
fn main() {
let mut running = false;
let mut callback = || {
if running { return };
running = true;
inputbot::KeySequence("Hello World").send();
// wait to make sure keyboard events are done.
sleep(Duration::from_millis(125));
running = false;
};
inputbot::KeybdKey::HKey.bind(callback);
inputbot::handle_input_events();
}
但是,这无法编译:
error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
经过一些阅读,我现在的理解是 Fn
闭包(inputbot 的 .bind()
方法需要)不能拥有任何可变数据,例如捕获的 mut
变量。
也许可以将变量包装在某种非 mut
值中?也许某种锁,使潜在的并发安全,就像这个 pseudocde?
fn main() {
let mut running = false;
let lockedRunning = example::Lock(&running);
let mut callback = || {
{
let mut running = lockedRunning.acquire();
if running { return };
running = true;
}
inputbot::KeySequence("Hello World").send();
// wait to make sure keyboard events are done.
sleep(Duration::from_millis(125));
{
let mut running = lockedRunning.acquire();
running = false;
}
};
}
这里你要的是函数本身是互斥的
Rust 允许您使用 Mutex
结构来执行此操作。它允许您持有一把锁,当获得该锁时,其他任何人都无法使用它,直到您释放它。
具体来说,您想要的功能是 try_lock
方法,该方法允许您检查是否已获取锁并允许您处理这种情况。
let lock = mutex.try_lock();
match lock {
Ok(_) => {
// We are the sole owners here
}
Err(TryLockError::WouldBlock) => return,
Err(TryLockError::Poisoned(_)) => {
println!("The mutex is poisoned");
return
}
}
使用原子值比 Mutex
简单一点,因为您无需担心失败情况,并且无需使用 lazy-static 即可轻松将其制成静态变量:
use std::sync::atomic::{AtomicBool, Ordering};
fn main() {
let is_being_called = AtomicBool::new(false);
bind(move || {
if !is_being_called.compare_and_swap(false, true, Ordering::SeqCst) {
print!("I'm doing work");
is_being_called.store(false, Ordering::SeqCst);
}
});
}
我预感这也比使用 Mutex
更有效,因为不需要进行堆分配,但我没有对其进行基准测试。
如果您处于单线程上下文中并且您的回调以某种方式(意外地?)递归(which closures cannot be),您还可以使用 Cell
:
use std::cell::Cell;
fn main() {
let is_being_called = Cell::new(false);
bind(move || {
if !is_being_called.get() {
is_being_called.set(true);
print!("doing work");
is_being_called.set(false);
}
})
}
如果你碰巧有一个 FnMut
闭包,你甚至不需要 Cell
并且可以只使用布尔值:
fn main() {
let mut is_being_called = false;
bind(move || {
if !is_being_called {
is_being_called = true;
print!("doing work");
is_being_called = false;
}
})
}