Concurrency 防止Fn在被调用时再次被调用';它已经在运行了

Concurrency 防止Fn在被调用时再次被调用';它已经在运行了,concurrency,macros,rust,keyboard-shortcuts,Concurrency,Macros,Rust,Keyboard Shortcuts,我正在使用编写一个程序,为我的计算机提供一些全局宏。例如,当我按h键时,它应该执行宏键入 你好,世界 进入当前应用程序。我试着这样实现它: extern crate inputbot; fn main() { let mut callback = || { inputbot::KeySequence("Hello World").send(); }; inputbot::KeybdKey::HKey.bind(callback); input

我正在使用编写一个程序,为我的计算机提供一些全局宏。例如,当我按h键时,它应该执行宏键入

你好,世界

进入当前应用程序。我试着这样实现它:

extern crate inputbot;

fn main() {
    let mut callback = || {
        inputbot::KeySequence("Hello World").send();
    };

    inputbot::KeybdKey::HKey.bind(callback);

    inputbot::handle_input_events();
}
然而,当我按下h键时,我实际得到的是:

哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈RLOWORWLWOWOWORO WORRWLOW ow ow ow ow ow OWLR ow ow ow ow ow WOWDLLOW ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow ow


宏每次发送h键事件时都会自动触发 这里需要的是函数本身是互斥的

Rust允许您对struct执行此操作。它允许你持有一把锁,当你获得它时,它会阻止其他人拿走它,直到你释放它

具体来说,您需要的功能是允许您检查锁是否已获得并允许您处理该情况的方法

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
    }
}

使用原子值比使用
互斥体要简单一些,因为您不需要担心失败的情况,并且可以轻松地将其转换为静态变量,而无需使用惰性静态:

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);
        }
    });
}
我有一种预感,这也比使用
互斥锁更有效,因为不需要进行堆分配,但我没有对其进行基准测试

如果您处于单线程上下文中,并且您的回调以某种方式(意外地?)递归(),那么您也可以使用
单元格

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
闭包,您甚至不需要
单元格
,只需使用布尔值:

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;
        }
    })
}

“我们毒害了互斥体”有点模棱两可。互斥锁实际上并没有被
try\u lock
毒害。这里有
RefCell
就足够了吗?我不清楚是否有线程在起作用。你可能是对的,我想知道如何才能得到交错,而不仅仅是一个无限循环。@MatthieuM。问题表明闭包作为回调函数工作,库可以从不同的线程调用它。@red75prime:我不知道这个特定的库,所以不知道它是否是多线程的:)你确定可以保证立即调用回调吗?如果不是,锁可能不是您想要的,因为第一次回调触发的回调可能在第一次回调返回后调用,因此它将能够获取锁并触发另一轮密钥strokes@SvenMarnach说得好,我认为,
inputbot
没有这样的保证。这比
try\u lock
更简单吗?我看到的主要区别是,你把中毒变成了僵局。@CodesInChaos你有什么建议我可以改进我的句子,在那里我陈述了我说得更简单的理由:“因为你不需要担心某些失败案例,它可以很容易地变成一个静态变量”?我也不知道你在哪里看到了僵局。。。你能再详细说明一下吗?你不必担心哪些失败案例?我能想到的唯一失败案例是锁内的代码死机,在这种情况下,解包
try\u lock
会因中毒的互斥死机而崩溃(易于调试)而您的锁将永远挂在下一次获取锁的尝试上。@CodesInChaos在第一个代码示例中没有任何
结果
,它不会失败。为什么它会永远挂着?如果块带有
println!(“再次发生”)执行时,原子变量已设置为
true
;以后所有读取变量的尝试都将返回
true
,函数将不会执行。我不知道你说的“获得锁”是什么意思;原子变量不是这样工作的。我把它误读为
,而
。但是,
如果
仍然具有类似的效果,则会默默地防止此代码在恐慌后再次运行。(通过获取锁,我指的是您的CAS指令,它对应于简单自旋锁的
try\u lock
操作)