我正在使用mlua
和Rust构建一个脚本引擎,一个脚本一次只能运行一个。我认为最好的方法是生成一个线程来运行每个脚本。线程不会返回任何数据,并且可以运行无限长的时间,直到用户停止它。
我的问题是如何在执行中停止线程?
例如,我的Lua脚本是无限的:
while true do
log("I'm stuck in an infinite loop!")
end
我当前的Rust代码如下所示:
pub struct Script {
name: String,
path: PathBuf,
lua: Arc<Mutex<Lua>>,
thread: ThreadManager,
should_stop: Arc<AtomicBool>,
}
impl Script {
pub fn new(name: &str, path: PathBuf) -> Result<Self> {
Ok(Self {
name: name.to_string(),
path,
lua: Arc::new(Mutex::new(Lua::new())),
thread: ThreadManager::new(),
should_stop: Arc::new(AtomicBool::new(false)),
})
}
pub fn load(&mut self) -> Result<()> {
let lua = self.lua.lock().unwrap();
let globals = lua.globals();
// register API functions here
globals.set(
"log",
lua.create_function(|_, msg: String| {
info!("{}", msg);
Ok(())
})?,
)?;
info!("Loaded script: {}", self.name);
Ok(())
}
pub fn start(&mut self) -> Result<()> {
let script_content = std::fs::read_to_string(&self.path);
let script_content = match script_content {
Ok(content) => content,
Err(_) => {
return Err(Error::RuntimeError(
"failed to read script file".to_string(),
));
}
};
let lua_arc_clone = Arc::clone(&self.lua);
let thread_state = self.thread.get_state(&self.name);
if thread_state == ThreadState::Stopped {
let is_started = self.thread.start(&self.name, move || {
let lua = lua_arc_clone.lock().unwrap();
lua.load(&script_content).exec().unwrap();
});
if !is_started {
warn!("failed to start thread for: {}", self.name);
}
}
Ok(())
}
pub fn stop(&mut self) -> Result<()> {
let thread_state = self.thread.get_state(&self.name);
if thread_state == ThreadState::Running {
self.thread.stop(&self.name);
info!("script stopped: {}", self.name);
}
Ok(())
}
}
要启动线程:
pub fn start<T>(&mut self, name: &str, t: T) -> bool
where
T: Fn() + Send + 'static,
{
let state = Arc::new(Mutex::new(ThreadState::Running));
let state_clone = Arc::clone(&state);
thread::spawn(move || loop {
match *state_clone.lock().unwrap() {
ThreadState::Running => {
info!("Running thread");
t();
}
ThreadState::Paused => {
info!("Paused thread");
thread::sleep(Duration::from_millis(10));
}
ThreadState::Stopped => {
info!("Stopped thread");
break;
}
}
});
self.threads.insert(name.clone().to_string(), state);
true
}
我试过使用信号,但问题是Lua执行阻塞了ofc的检查。
1条答案
按热度按时间e37o9pze1#
您可以调用
Thread::reset
来终止它。或者,如果您切换到异步,您可以
drop
AsyncThread
以获得类似的效果。另一种选择是使用
debug.sethook
强制Lua VM中断并将控制权交还给Rust代码,但是我认为这会减慢Lua代码的速度,因为它会不断中断自己并等待Rust程序恢复它。