微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将 Glib 主循环集成到 libev 事件循环中C++

如何解决将 Glib 主循环集成到 libev 事件循环中C++

我正在尝试将 Glib 主循环集成到 libev 事件循环中。实际上,我正在使用他们的 C++ 包装器:glibmm [1] 和 ev++ [2]。主要思想来自 EV::Glib Perl 模块 [3]。但是,当我尝试执行一些异步任务(例如,从文件系统读取文本文件)时,我的实现有时会挂起:

#include <ev++.h>
#include <giomm.h>
#include <glibmm.h>

struct context;

int to_ev_events(Glib::IOCondition events) {
  int result = EV_NONE;
  if ((events & Glib::IOCondition::IO_IN) != Glib::IOCondition{})
    result |= EV_READ;
  if ((events & Glib::IOCondition::IO_OUT) != Glib::IOCondition{})
    result |= EV_WRITE;
  return result;
}

Glib::IOCondition to_glib_events(int events) {
  Glib::IOCondition result{};
  if ((events & EV_READ) != EV_NONE) result |= Glib::IOCondition::IO_IN;
  if ((events & EV_WRITE) != EV_NONE) result |= Glib::IOCondition::IO_OUT;
  return result;
}

struct prepare_watcher {
  prepare_watcher(context &c) : ctx{c} {
    watcher.priority = EV_MINPRI;
    watcher.set(this);
    watcher.start();
  }
  void operator()(ev::prepare &watcher,int revents);
  ev::prepare watcher;
  context &ctx;
};

struct check_watcher {
  check_watcher(context &c) : ctx{c} {
    watcher.priority = EV_MAXPRI;
    watcher.set(this);
    watcher.start();
  }
  void operator()(ev::check &watcher,int revents);
  ev::check watcher;
  context &ctx;
};

struct timer_watcher {
  timer_watcher() { watcher.priority = EV_MINPRI; }
  ev::timer watcher;
};

struct io_watcher {
  io_watcher(int fd,int events) {
    watcher.priority = EV_MINPRI;
    watcher.start(fd,events);
  }
  ev::io watcher;
};

struct context {
  Glib::RefPtr<Glib::MainContext> context = Glib::MainContext::get_default();
  ev::default_loop loop;
  std::vector<Glib::PollFD> poll_fds;
  int priority{};
  prepare_watcher prepare{*this};
  check_watcher check{*this};
  timer_watcher timer;
  std::map<int,io_watcher> ios;
};

void prepare_watcher::operator()(ev::prepare &watcher,int revents) {
  ctx.context->dispatch();
  ctx.context->prepare(ctx.priority);
  ctx.poll_fds.clear();
  int timeout = 0;
  ctx.context->query(ctx.priority,timeout,ctx.poll_fds);
  for (Glib::PollFD &poll_fd : ctx.poll_fds) {
    int fd = poll_fd.get_fd();
    ctx.ios.try_emplace(fd,fd,to_ev_events(poll_fd.get_events()));
  }
  if (timeout >= 0) ctx.timer.watcher.start(timeout * 1e-3);
}

void check_watcher::operator()(ev::check &watcher,int revents) {
  for (Glib::PollFD &poll_fd : ctx.poll_fds) {
    int fd = poll_fd.get_fd();
    io_watcher &io = ctx.ios.at(fd);
    if (io.watcher.is_pending())
      poll_fd.set_revents(
          to_glib_events(ev_clear_pending(ctx.loop.raw_loop,&io.watcher)));
    ctx.ios.erase(fd);
  }
  if (ctx.timer.watcher.is_active() || ctx.timer.watcher.is_pending())
    ctx.timer.watcher.stop();
  ctx.context->check(ctx.priority,ctx.poll_fds);
}

int main() {
  Gio::init();
  context ctx;
  Glib::RefPtr<Gio::File> file = Gio::File::create_for_path("file.txt");
  file->read_async([&](Glib::RefPtr<Gio::AsyncResult> result) {
    file->read_finish(result);
    ctx.loop.break_loop(ev::ALL);
  });
  ctx.loop.run();
}

有什么想法吗?

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。