Vala+GTK3开发中如何正确等待布尔变量状态变更且不阻塞程序
问题根因
直接在注释位置加while循环等待会卡死的核心原因是GTK基于单线程事件驱动模型,所有回调(包括你注册的Timeout超时回调)都需要等主线程的Gtk.main()启动事件循环之后才能被调度执行。如果在主线程写死等的空循环,主线程会被完全占住,永远没有机会执行超时回调,done变量永远不会被置为true,自然就会无限卡住。
解决方案
方案1:把后续逻辑移到回调中(官方推荐写法)
这是最符合GTK设计规范的实现方式,不需要额外写等待逻辑,直接把需要等done为true之后执行的逻辑放到回调触发的时序中即可:
private bool done = false; private void test (GLib.SourceFunc after_done) { GLib.Timeout.add(1000, () => { done = true; print("\ndone\n"); // 执行等待完成后的逻辑 after_done(); Gtk.main_quit (); return false; }); return; } public void main () { test(() => { // 原本需要等待后执行的逻辑放在这里 print(done.to_string ()); return false; }); Gtk.main (); }
运行命令为vala minimal.vala --pkg gtk+-3.0,执行后会先等待1秒输出done,再输出true,符合预期。
方案2:手动迭代事件循环实现原地等待
如果确实需要在原注释位置原地等待、不希望拆分逻辑,可以在等待循环中手动执行事件循环迭代,不会卡住回调触发:
private bool done = false; private void test () { GLib.Timeout.add(1000, () => { done = true; print("\ndone\n"); Gtk.main_quit (); return false; }); return; } public void main () { test (); // 原地等待done为true,同时处理事件循环避免卡住回调 while (!done) { // 手动迭代一次主循环,处理所有待触发的事件 GLib.MainContext.default().iteration(true); } print(done.to_string ()); Gtk.main (); }
该写法可以实现原地等待的效果,同时不会阻塞超时回调的正常触发。
内容的提问来源于stack exchange,提问作者ChildishGiant
相关产品推荐
相关产品推荐

