1 GMainLoop、GMainContext、GSource

1.1 三者之间关系

  • GMainLoop -> GMainContext -> {GSource1, GSource2,GSource3… }
  • 每个GMainLoop都包含一个GMainContext成员,而这个GMainContext成员可以装各种各样的GSource,GSource则是具体的各种Event处理逻辑了。在这里,可以把GMainContext理解为GSource的容器,但是它的用处不只是装GSouce。
  • 创建GMainLoop使用函数g_main_loop_new,他的第一个参数就是需要关联的GMainContext,如果这个值为空,程序会分配一个默认的Context给GMainLoop,把GSource加到GMainContext使用g_source_attach。
  • g_main_loop_new创建一个main loop对象,一个main loop对象只能被一个线程使用,但一个线程可以有多个main loop对象。
  • GLib内部实现了几种类型的事件源,分别是文件描述符(文件、管道和socket)、超时idle事件自定义事件

1.2 GMainContext

  为了让多组独立事件源能够在不同的线程中被处理,每个事件源都会关联一个GMainContext。一个线程只能运行一个GMainContext,都是在其他线程中能够对事件源进行添加和删除操作。

GMainConText涉及的内容比较多,在后面章节相似介绍。

2 事件源

注意:在事件源回调函数function中,如果回调函数返回值是FALSE,该事件源将被删除;反则该事件源会在没有更高优先级事件时,再次运行。

2.1 超时事件源

guint    g_timeout_add              (guint           interval,GSourceFunc     function,gpointer        data);

2.2 空闲函数事件源

添加一个在默认主循环中没有高优先级事件待决时调用的函数。该函数具有默认的空闲优先级G_PRIORITY_DEFAULT_IDLE。如果函数返回FALSE,它将自动从事件源列表中删除,并且不会再次调用。

关于如何处理返回值和数据的内存管理,请参阅[内存管理][mainloop-memory-management]。

这在内部使用g_idle_source_new()创建了一个主循环源,并使用g_source_attach()将其附加到全局GMainContext,因此无论哪个线程运行该主上下文,都会调用回调函数。如果需要更好的控制或使用自定义的主要上下文,可以手动执行这些步骤。

该函数不能直接用于语言绑定。

这个方法的实现由语言绑定中的g_idle_add_full()提供

guint    g_idle_add                 (GSourceFunc     function,gpointer        data);

2.3 描述字事件源

#include <glib.h>
#include <gio/gio.h> /* gio channel */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>gboolean
client_recv (GIOChannel   *source, GIOCondition  condition,gpointer      data){gchar buff[128];gint recv_byte = 128;gint recv_sizing;gint clienct_insock = g_io_channel_unix_get_fd(source);recv_sizing = recv(clienct_insock, buff, recv_byte, 0);if(recv_sizing < 0 || recv_sizing == 0){g_print("connection lost or error while recv(); [just guess] number : %d\n", recv_sizing);close(clienct_insock);return FALSE;}buff[recv_sizing] = '\0';g_print("data: %s\n", buff);return TRUE;
}gboolean
deal(GIOChannel *in, GIOCondition condition, gpointer data){struct sockaddr_in income;gint insock = g_io_channel_unix_get_fd(in);socklen_t income_len = sizeof(income);/*接受请求*/gint newsock = accept(insock, (struct sockaddr*)&income, &income_len);if(newsock == -1){g_print("failure on newsock\n");} g_print("Linked successfully\n");/*得到客户端描述字*/GIOChannel *client_in = g_io_channel_unix_new(newsock);/*添加到主循环事件*/g_io_add_watch(client_in,G_IO_IN | G_IO_OUT | G_IO_HUP,(GIOFunc)client_recv,NULL);return TRUE;
}int
main(int argc, char *argv[]){GIOChannel *in;/*打开一个网络通讯端口,如果成功的话就像open()一样返回一个文件描述符*/gint rsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if(rsock < 0){g_printerr("socket\n");return 1;}/*绑定端口号*/struct sockaddr_in my;my.sin_family = AF_INET;/* 套接口地址结构的地址 */my.sin_addr.s_addr = inet_addr("10.112.86.5");my.sin_port = htons(8080);gint ret = bind(rsock, (struct sockaddr *)&my, sizeof(my));if(ret < 0){g_printerr("bind\n");return 1;}/*开始监听*/ret = listen(rsock, 10);if(ret < 0){g_printerr("listen\n");return 1;}/*通过文件描述字得到GIOChannel*/in = g_io_channel_unix_new(rsock);/*添加到主循环事件*/g_io_add_watch(in,G_IO_IN | G_IO_OUT | G_IO_HUP,(GIOFunc)deal,NULL);GMainLoop *loop = g_main_loop_new(NULL, FALSE);g_main_loop_run(loop);return 0;
}

2.4 Child Watch

#include<glib.h>gboolean
source_prepare_cb(GSource *source, gint *timeout){g_print("prepare\n");*timeout = 1000;return FALSE;
}gboolean
source_check_cb(GSource *source){g_print("check\n");return TRUE;
}gboolean
source_dispatch_cb(GSource *source,GSourceFuncs callback,gpointer data){g_print("dispatch\n");callback(data);return TRUE;
}void
source_finalize_cb(GSource *source){g_print("finalize\n");
}void
myidle(gpointer data){g_print("myidle\n");
}int
main(int argc, char *argv[]){GMainLoop *loop = g_main_loop_new(NULL, FALSE);GMainContext *context = g_main_loop_get_context(loop);GSourceFuncs g_source_myidle_funcs = {source_prepare_cb,source_check_cb,source_dispatch_cb,source_finalize_cb,};/* 创建新事件源实例,传入了事件的函数表、事件结构体大小 */GSource *source = g_source_new(&g_source_myidle_funcs, sizeof(GSource));/* 设置新事件源source的回调函数 */g_source_set_callback(source, (GSourceFunc)myidle, "Hello, world!", NULL);/* source关联特定的GMainContext对象 */g_source_attach(source, context);g_source_unref(source);g_main_loop_run(loop);g_main_context_unref(context);g_main_loop_unref(loop);return 0;
}

3 代码

3.1 空闲事件源和超时事件源

#include<glib.h>/*** FALSE,该事件源将被删除* TRUE,该事件源在没有更高优先级事件时,再次运行
*/
gboolean
count_down(gpointer data){static int count = 10;if(count < 1){g_print("count_down return FALSE\n");return FALSE;}g_print("count_down %4d\n", count--);return TRUE;
}gboolean
cancel_fire(gpointer data){GMainLoop *loop = data;g_print("cancel_fire() quit \n");g_main_loop_quit(loop);return FALSE;
}gboolean
say_idle(gpointer data){g_print("say_idle() \n");/*该超时事件源只调用一次,因为返回FALSE系统自动删除该事件源*/return FALSE;
}int
main(int argc, char *argv[]){/* 每个事件源都会关联一个GMainContext,一个线程只能运行一个GMainContext* 但是其他线程中能够对事件源进行添加和删除操作*/GMainContext *context;GMainLoop *loop = g_main_loop_new(NULL, FALSE);/*添加超时事件源*/g_timeout_add(1000, count_down, NULL);g_timeout_add(8000, cancel_fire, loop);/*添加一个空闲函数*/g_idle_add(say_idle, NULL);g_main_loop_run(loop);g_main_loop_unref(loop);return 0;
}

参考1:Glib主事件循环轻度分析与编程应用
参考2:GLib IO Channels Reference Manual

七、GLib主要的事件循环(The Main Event Loop)相关推荐

  1. Glib学习(22) 主事件循环 The Main Event Loop

    glib源码下载:http://ftp.gnome.org/pub/gnome/sources/glib/ glib帮助文档:https://developer.gnome.org/glib/ 主事件 ...

  2. 【转载】浏览器事件循环机制(event loop)

    首先,本文转自https://juejin.im/post/5afbc62151882542af04112d 当我看完菲利普·罗伯茨的 javascript event loop的演讲的时候,就对于事 ...

  3. 笔试题——JavaScript事件循环机制(event loop、macrotask、microtask)

    今天做了一道笔试题觉得很有意义分享给大家,题目如下: setTimeout(()=>{console.log('A'); },0); var obj={func:function () {set ...

  4. node mysql 事件循环_NodeJs 的 Event loop 事件循环机制详解

    什么是事件轮询 事件循环是 Node.js 处理非阻塞 I/O 操作的机制--尽管 JavaScript 是单线程处理的--当有可能的时候,它们会把操作转移到系统内核中去. 下面的图表显示了事件循环的 ...

  5. 事件循环机制 (Event Loop)

    事件循环机制从整体上告诉了我们 JavaScript 代码的执行顺序Event Loop即事件循环,是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是我们经常使用 ...

  6. JavaScript中事件循环的理解 Event Loop

    为了解决单线程运行阻塞问题,JavaScript用到了计算机系统的一种运行机制,这种机制就叫做事件循环(Event Loop) 事件循环(Event Loop) 在JavaScript中,所有的任务都 ...

  7. 彻底搞懂JS事件循环机制(event loop)

    知识点: js异步实现 EventLoop.消息队列 宏任务 与 微任务 同步模式与异步模式 首先要确定 js是单线程语言,js在设计之初用作用户互动,以及操作DOM.这决定了它只能是单线程(例如多线 ...

  8. 八七、Node.js事件循环与多进程

    nodejs事件循环与多进程 why 事件循环对于深入理解nodejs异步至关重要 fs, net,http,events 事件循环是企业面试中的最高频考题之一 能驾驭nodejs多进程是一名资深前端 ...

  9. 事件循环机制EventLoop

    事件循环机制EventLoop Event Loop即事件循环,是解决javaScript单线程运行阻塞的一种机制. 一.EventLoop的相关概念 1.堆(Heap) 堆表示一大块非结构化的内存区 ...

最新文章

  1. JAVA 多线程实现包子铺(买包子,吃包子)
  2. Leangoo用户设置在哪里?
  3. 宝塔服务器环境好不好_服务器环境怎么搭建?(宝塔环境搭建教程)
  4. LINUX学习笔记高度浓缩版之一 :用户管理、启动过程、硬盘管理
  5. fedora,linux mint 命令行(终端)打开目录
  6. SDUTRescue The Princess(数学问题)
  7. 递归-递归的特点及基本代码演练
  8. 13.简述MYSQL的权限级别_MySQL权限级别
  9. android 怎么自定义任务栈,Android中的Activity详解--启动模式与任务栈
  10. 定时任务 Wpf.Quartz.Demo.3
  11. 查找你的幸运守护精灵
  12. 《on Java 中文版》读后感(《JAVA编程思想》的原作者)(JAVA 小虚竹)
  13. 利用Netica训练简易贝叶斯网络模型【教程】
  14. html代码中font是什么意思,HTML元素font标签的使用方法及作用
  15. 7系列FPGA数据手册:概述------中文翻译版
  16. 淘宝直播医美,颜值经济崛起,如何抢占流量风口
  17. Python matplotlib 堆叠图
  18. go get connectex: A connection attempt failed because the connected party did not properly respond
  19. 以太坊源码分析(10)CMD深入分析
  20. 分享了一篇文章:《格子出位nbsp;要你好看》

热门文章

  1. JetBrains 发布新款编程字体,提高编程效率、开源免费可商用!
  2. 雷达模拟器 SPx Radar Simulator
  3. 把mysql结果转换成数组实例
  4. 如何为机器视觉选择合适的采集卡
  5. 实时监测GPU的显存和显存清理小功能学习
  6. 中国科学院计算机在职研究生怎么样,中科大在职研究生好考吗,考进中科院的人很牛逼吗?...
  7. 阿里巴巴Java开发手册(纪念版 1.3.1)记录
  8. 域名交易谈判技巧:怎么给心仪域名还价?
  9. Detectron2入门:Ubuntu 20.04上安装Detectron2
  10. 对抗生成网络原理和作用