Gobject tutorial 十

参考:GLib – 2.0: The Main Event Loop

The Main Event Loop

主事件循环管理所有可用的事件源,事件可以是各种类型、各种数量的。比如说文件描述符(普通文件、管道以及套接字)和超时。

新类型的事件源可以通过函数g_source_attach来添加。为了使多个相互独立的事件源集能在不同的线程中进行处理,每个事件源都会关联一个GMainContext。一个GMainContext只能在一个线程中运行,但, 事件源可以添加到一个线程中的GmainContext,而从另外一个线程中移除。

我们来先来看看GLib中对事件源的定义。

struct _GSource
{
  /*< private >*/
  gpointer callback_data;
  GSourceCallbackFuncs *callback_funcs;

  const GSourceFuncs *source_funcs;
  guint ref_count;

  GMainContext *context;

  gint priority;
  guint flags;
  guint source_id;

  GSList *poll_fds;
  
  GSource *prev;
  GSource *next;

  char    *name;

  GSourcePrivate *priv;
};

由定义可以看到,事件源的定义中包含 GMainContext,结构体中还包含成员priority,这表示每个事件源都被指定一个优先级,默认的优先级是G_PRIORITY_DEFAULT,其值为0,当优先级的值小于0表示高优先级,高优先级的事件源优先处理。

GMainLoop 用于表示主事件循环。它由函数g_main_loop_new()函数创建。在为其添加完事件后,调用函数g_main_loop_run()来运行主事件循环。从代码层面上看,GMainLoop就是一个loop,在loop中它,循环会运行GMainContext来持续检查事件源中的事件并对事件进行分发。最终,会有一个事件源中的事件导致函数g_main_loop_quit()被调用,这就意味着程序退出主循环,函数g_main_loop_run()返回。

我们看一下GLib中GMainLoop是如何定义的。

struct _GMainLoop
{
  GMainContext *context;
  gboolean is_running; /* (atomic) */
  gint ref_count;  /* (atomic) */
};
/**
 * g_main_loop_run:
 * @loop: a #GMainLoop
 * 
 * Runs a main loop until g_main_loop_quit() is called on the loop.
 * If this is called for the thread of the loop's #GMainContext,
 * it will process events from the loop, otherwise it will
 * simply wait.
 **/
void 
g_main_loop_run (GMainLoop *loop)
{
......
  g_atomic_int_set (&loop->is_running, TRUE);
  while (g_atomic_int_get (&loop->is_running))
    g_main_context_iterate_unlocked (loop->context, TRUE, TRUE, self);
......
}

 Creating new source types

GMainLoop允许创建和使用不同于GLib中内置的事件源类型的事件源。

新的事件源类型要继承自GSource结构,与GObject中的有继承关系的数据结构的成员的写法类似,新的事件源类型的数据结构的第一个成员是GSource。创建新的事件源类型实例是通过函数g_source_new()实现的。函数的第一个参数GsourceFuncs中的函数决定了新事件源类型的功能。

GLIB_AVAILABLE_IN_ALL
GSource *g_source_new             (GSourceFuncs   *source_funcs,
                                   guint           struct_size);

我们举例看看在GTK中,新事件源类型数据结构的定义情况。

typedef struct _GdkMacosEventSource
{
  GSource     source;
  GdkDisplay *display;
} GdkMacosEventSource;

 新的事件源类型与其所属GMainContext之间有两种交互方式。第一种方式是通过GSourceFuncs结构中的prepare函数设置一个超时,来指定在主事件循环在检查此事件源之前最大的睡眠时间,另一种方式是,事件源通过调用函数g_source_add_poll()将文件描述符添加到集合中,GMainContext会对集合进行检查。

GSourceFuncs结构的定义如下:

/**
 * GSourceDummyMarshal:
 *
 * This is just a placeholder for #GClosureMarshal,
 * which cannot be used here for dependency reasons.
 */
typedef void (*GSourceDummyMarshal) (void);

struct _GSourceFuncs
{
  gboolean (*prepare)  (GSource    *source,
                        gint       *timeout_);/* Can be NULL */
  gboolean (*check)    (GSource    *source);/* Can be NULL */
  gboolean (*dispatch) (GSource    *source,
                        GSourceFunc callback,
                        gpointer    user_data);
  void     (*finalize) (GSource    *source); /* Can be NULL */

  /*< private >*/
  /* For use by g_source_set_closure */
  GSourceFunc     closure_callback;        
  GSourceDummyMarshal closure_marshal; /* Really is of type GClosureMarshal */
};

Customizing the main loop iteration

函数g_main_context_iteration()就能实现单纯的GMainContext迭代。然而,很多时候,我们需要对主事件循环的运行增加精确控制。比如说,GMainLoop在迭代时使用了另外一个主事件循环,此时,你可以调用g_main_context_iteration()的组成函数g_main_context_prepare(), g_main_context_query(), g_main_context_check() and g_main_context_dispatch()。

State of a Main Context

MainContext的状态图如下:

 Main Contexts

What is GMainContext?

GMainContexts是对事件循环的一个通用实现。一个GMaintext会有多个事件源与之相关,每个事件源都可以被认为是一个拥有回调函数的事件,当事件发生时,回调函数就会执行,也可以认为是一个待检测的文件描述符集。例如,超时可以是一个事件,从套接字上首受到的数据也可以是一个事件。

我们来看看GMainContext的定义。

struct _GMainContext
{
  /* The following lock is used for both the list of sources
   * and the list of poll records
   */
  GMutex mutex;
  GCond cond;
  GThread *owner;
  guint owner_count;
  GMainContextFlags flags;
  GSList *waiters;

  gint ref_count;  /* (atomic) */

  GHashTable *sources;              /* guint -> GSource */

  GPtrArray *pending_dispatches;
  gint timeout;			/* Timeout for current iteration */

  guint next_id;
  GList *source_lists;
  gint in_check_or_prepare;

  GPollRec *poll_records;
  guint n_poll_records;
  GPollFD *cached_poll_array;
  guint cached_poll_array_size;

  GWakeup *wakeup;

  GPollFD wake_up_rec;

/* Flag indicating whether the set of fd's changed during a poll */
  gboolean poll_changed;

  GPollFunc poll_func;

  gint64   time;
  gboolean time_is_fresh;
};

一个完整的事件循环会经过一下几个步骤,如上图所示:

  1. 准备事件源。这个步骤用于确定事件源中是否有准备好立即分发事件的事件源

  2.监听事件源。阻塞当前线程,直到事件源中有事件发生。

  3.检查哪个源中有事件发生。

  4.从事件源中分发回调函数。

对于上述的步骤,我们来看看GLib中的实现。

/**
 * g_main_context_iteration:
 * @context: (nullable): a #GMainContext (if %NULL, the global-default
 *   main context will be used)
 * @may_block: whether the call may block.
 *
 * Runs a single iteration for the given main loop. This involves
 * checking to see if any event sources are ready to be processed,
 * then if no events sources are ready and @may_block is %TRUE, waiting
 * for a source to become ready, then dispatching the highest priority
 * events sources that are ready. Otherwise, if @may_block is %FALSE
 * sources are not waited to become ready, only those highest priority
 * events sources will be dispatched (if any), that are ready at this
 * given moment without further waiting.
 *
 * Note that even when @may_block is %TRUE, it is still possible for
 * g_main_context_iteration() to return %FALSE, since the wait may
 * be interrupted for other reasons than an event source becoming ready.
 *
 * Returns: %TRUE if events were dispatched.
 **/
gboolean
g_main_context_iteration (GMainContext *context, gboolean may_block)
{
  gboolean retval;

  if (!context)
    context = g_main_context_default();
  
  LOCK_CONTEXT (context);
  retval = g_main_context_iterate_unlocked (context, may_block, TRUE, G_THREAD_SELF);
  UNLOCK_CONTEXT (context);
  
  return retval;
}


/* HOLDS context lock */
static gboolean
g_main_context_iterate_unlocked (GMainContext *context,
                                 gboolean      block,
                                 gboolean      dispatch,
                                 GThread      *self)
{
......

  g_main_context_prepare_unlocked (context, &max_priority);
  
  while ((nfds = g_main_context_query_unlocked (
            context, max_priority, &timeout, fds,
            allocated_nfds)) > allocated_nfds)
    {
......
    }

......
  g_main_context_poll_unlocked (context, timeout, max_priority, fds, nfds);
  
  some_ready = g_main_context_check_unlocked (context, max_priority, fds, nfds);
  
  if (dispatch)
    g_main_context_dispatch_unlocked (context);
  
......

  return some_ready;
}

GMainContext的核心,其实就是一个poll()循环,prepare函数作为循环的先导,check和disapatch函数作为后续。

static void
g_main_context_poll_unlocked (GMainContext *context,
                              int           timeout,
                              int           priority,
                              GPollFD      *fds,
                              int           n_fds)
{
......

      poll_func = context->poll_func;
       ......
}

在用户没有调用函数g_main_context_set_poll_func设置poll_func时,GLib的默认poll_func为g_poll.

void
g_main_context_set_poll_func (GMainContext *context,
			      GPollFunc     func)
{
  if (!context)
    context = g_main_context_default ();
  
  g_return_if_fail (g_atomic_int_get (&context->ref_count) > 0);

  LOCK_CONTEXT (context);
  
  if (func)
    context->poll_func = func;
  else
    context->poll_func = g_poll;

  UNLOCK_CONTEXT (context);
}


/**
 * g_poll:
 * @fds: file descriptors to poll
 * @nfds: the number of file descriptors in @fds
 * @timeout: amount of time to wait, in milliseconds, or -1 to wait forever
 *
 * Polls @fds, as with the poll() system call, but portably. (On
 * systems that don't have poll(), it is emulated using select().)
 * This is used internally by #GMainContext, but it can be called
 * directly if you need to block until a file descriptor is ready, but
 * don't want to run the full main loop.
 *
 * Each element of @fds is a #GPollFD describing a single file
 * descriptor to poll. The @fd field indicates the file descriptor,
 * and the @events field indicates the events to poll for. On return,
 * the @revents fields will be filled with the events that actually
 * occurred.
 *
 * On POSIX systems, the file descriptors in @fds can be any sort of
 * file descriptor, but the situation is much more complicated on
 * Windows. If you need to use g_poll() in code that has to run on
 * Windows, the easiest solution is to construct all of your
 * #GPollFDs with g_io_channel_win32_make_pollfd().
 *
 * Returns: the number of entries in @fds whose @revents fields
 * were filled in, or 0 if the operation timed out, or -1 on error or
 * if the call was interrupted.
 *
 * Since: 2.20
 **/
gint
g_poll (GPollFD *fds,
	guint    nfds,
	gint     timeout)
{
  return poll ((struct pollfd *)fds, nfds, timeout);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/742249.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

硬件开发笔记(十九):Altium Designer 21软件介绍和安装过程

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/139706278 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

java运维交接项目逆向工程

​ 背景 有承接过Java项目运维的团队估计都处理过的一件事情&#xff0c;就是同步生产代码跟本地代码&#xff0c;条件再差些甚至要直接基于生产部署包逆向本地源码工程。而哪怕是原运维团队交接了源码&#xff0c;往往也会历史久远的原因&#xff0c;给了一份不太可靠的源码…

数字心动+华为运动健康服务 使用体验指导

一、应用介绍 “数字心动”是一个体育生态平台APP&#xff0c;践行“体育大健康娱乐数字营销”模式&#xff0c;打造深度融合体育平台。APP集跑步运动记录、赛事活动报名、成绩/大众等级证书查询等多功能于一体&#xff0c;采取“线上线下”模式&#xff0c;结合协会、行业、品…

飞睿uwb芯片厂商,室内轨迹跟踪定位模块,人员、车辆和物资定位测距数据传输

在科技日新月异的今天&#xff0c;定位技术已经渗透到了我们生活的方方面面。从智能手机到自动驾驶汽车&#xff0c;再到智能仓储管理&#xff0c;定位技术都发挥着不可或缺的作用。然而&#xff0c;传统的GPS定位技术在室内环境中往往面临信号受阻、精度不足等问题。此时&…

echarts旭日图添加图例

研究了好久终于弄出来了&#xff0c;上代码&#xff0c;代码可以直接copy到官网去试&#xff0c;看看效果。 var data [{name: Grandpa,children: [{name: Uncle Leo,value: 15,children: [{name: Cousin Jack,value: 2},{name: Cousin Mary,value: 5,children: [{name: Jacks…

uniapp(全端兼容) - 最新详细实现刻度尺组件效果,uni-app实现尺子打分及手指拖动刻度尺打分评分功能,可左右滑动刻度尺改变数值、带刻度尺滑块功能、

效果图 在uniapp微信小程序/手机h5网页网站/安卓app/苹果app/支付宝小程序/nvue等(全平台完美兼容)开发中,实现uniApp各端都兼容的 “刻度尺(横格尺 | 尺子)” 手势左右两侧拖动、手指滑动刻度尺功能,水平刻度尺,支持自定义尺子颜色、大小、刻度、滑动时的步进值、最大…

大模型微调方法总结

一 LoRA&#xff1a; 1 低(秩)rank 自适应微调方法 2 背景及本质   大模型的参数更新耗费大量现存为此&#xff0c; 微软的研究者们于2021年通过论文《LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS》提出了低秩适应LoRA 它冻结了预训练的模型权重&#xff0c;并将可…

c语言常用易错记录

c语言常用易错记录 文章目录 c语言常用易错记录1.for循环 1.for循环 示例&#xff1a; #include <stdio.h>int main() {int i;for (i 0; i < 10; i) {printf("%d\n", i);}return 0; }执行顺序 备注&#xff1a;此图来源于b站鹏哥C语言视频课截图&#xf…

暴雨虐长沙,生灵受煎熬

今天&#xff0c;“湖南长沙市遭遇强降雨,一小时的降雨量足够注满54个西湖”这消息&#xff0c;终于登上互联网社交平台热搜榜。 截图&#xff1a;来源社交网站 综合多家媒体消息概述如下。 昨&#xff08;24日&#xff09;天&#xff0c;湖南长沙市遭遇强降雨&#xff0c;一…

odoo17 tree视图添加按钮

需求描述 点击下图中tree视图上的同步退货单按钮&#xff0c;弹出相应的form视图进行退货单同步&#xff0c;然后点击同步按钮调用后端python代码处理。 实现步骤 主要文件目录结构 js文件的创建 /** odoo-module **/ import { registry } from "web/core/registry&quo…

SM7055-18明微电子12/18V低成本 BUCK,BUCK-BOOST电源芯片方案

深圳市三佛科技有限公司分享SM7055-18 是采用电流模式 PWM 控制方式的功率开关芯片&#xff0c;集成高 压启动电路和高压功率管&#xff0c;可实现低成本、高性价比开关电源系统解决 方案。芯片应用于 BUCK、BUCK-BOOST 系统方案&#xff0c;支持 18V 输出电压&#xff0c;很 方…

vxe-list做列表虚拟滚动时,底部间距的优化

已知vxe-list在数据超出一定行时会自动启用纵向虚拟滚动配置&#xff0c;默认效果如图&#xff1a; 但是在滚动中我们发现有时列表底部间距不一致&#xff0c;而且会出现在感官上底部空白过多的情况&#xff1a; 这时候我们想让列表恰好显示完全应该怎么做呢&#xff0c;查看官…

2024年6月24日 (周一) 叶子游戏新闻

图吧工具箱: 全名图拉丁吧硬件检测工具箱,是开源、免费、绿色、纯净的硬件检测工具合集,专为图钉及所有DIY爱好者制作,包含常用硬件测试和检测工具,月工JS必备! 土豆录屏: 免费、无录制时长限制、无水印的录屏软件 高手在民间 粉丝玩家打造精美《黄金树幽影》巨大插画虽然不是专…

Qt项目天气预报(7) - 更新一周天气(数据和图像)

更新七天JSON信息 调用API : 专业七日天气v9:/ /同前文需要先 易客云天气API免费天气API接口|天气预报接口|全球天气API接口|气象预警|空气质量 (tianqiapi.com)注册生成自己的api http://v1.yiketianqi.com/api?unescape1&versionv9&appid65521391&appsecretDv2e…

如何做好药店布局,实现客流回归?

随着我国医药市场的不断发展&#xff0c;药店数量逐年增多&#xff0c;竞争愈发激烈。在这种背景下&#xff0c;如何做好药店布局&#xff0c;吸引客流回归&#xff0c;成为药店经营者关注的核心问题。 要想实现店铺形象美观大方、有效引导客流动向&#xff0c;增加顾客在店内…

在动作电影中,如何使用动捕来完成替身演员打戏

随着电影技术的飞速发展&#xff0c;动作电影的制作也日益追求真实与震撼的视觉效果。在这样的背景下&#xff0c;动作捕捉&#xff08;Motion Capture&#xff0c;简称动捕&#xff09;技术成为了制作高质量动作电影的重要工具之一。尤其在替身演员打戏的拍摄中&#xff0c;动…

【SQL Server点滴积累】Setup SQL Server 2008 Database Mirror (二)

【SQL Server点滴积累】Setup SQL Server 2008 Database Mirror (一)-CSDN博客今天分享SQL Server 2008 R2搭建数据库镜像(Database Mirror)https://blog.csdn.net/ncutyb123/article/details/139749117?spm1001.2014.3001.5501本篇Blog基于以上Blog步骤进行SQL Server 2008 R…

红酒品鉴秘籍:一键解锁味觉宇宙,开启你的味觉探险新纪元

红酒&#xff0c;这种优雅的液体&#xff0c;蕴藏着丰富的口感和层次&#xff0c;每一次的品鉴都是一次味觉的探险。今天&#xff0c;就让我们一起探索红酒品鉴的奥秘&#xff0c;解锁味觉的新世界&#xff0c;而在这个过程中&#xff0c;雷盛红酒将成为我们的向导&#xff0c;…

大模型训练十大戒律!!

1.切勿微调&#xff08;Thou Shalt Not Fine-Tune&#xff09;&#xff1a;尽量写prompt&#xff0c;利用大模型本身的能力zeroshot&#xff0c;必要时辅以少量样本&#xff08;few-shot examples&#xff09;或检索增强生成&#xff08;RAG&#xff09;。微调成本高、速度慢且…

Java也能做OCR!SpringBoot 整合 Tess4J 实现图片文字识别

文章目录 1. 环境准备1.1 安装 Tesseract OCR 引擎1.2 引入 Tess4J 依赖 2. 创建 Spring Boot 项目2.1 初始化项目2.2 目录结构 3. 编写 OCR 功能代码3.1 创建服务层3.2 创建控制器层 4. 配置 Tesseract 语言包5. 运行和测试5.1 启动 Spring Boot 应用5.2 使用 Postman 或 cURL…