七、GLib主要的事件循环(The Main Event Loop)
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)相关推荐
- Glib学习(22) 主事件循环 The Main Event Loop
glib源码下载:http://ftp.gnome.org/pub/gnome/sources/glib/ glib帮助文档:https://developer.gnome.org/glib/ 主事件 ...
- 【转载】浏览器事件循环机制(event loop)
首先,本文转自https://juejin.im/post/5afbc62151882542af04112d 当我看完菲利普·罗伯茨的 javascript event loop的演讲的时候,就对于事 ...
- 笔试题——JavaScript事件循环机制(event loop、macrotask、microtask)
今天做了一道笔试题觉得很有意义分享给大家,题目如下: setTimeout(()=>{console.log('A'); },0); var obj={func:function () {set ...
- node mysql 事件循环_NodeJs 的 Event loop 事件循环机制详解
什么是事件轮询 事件循环是 Node.js 处理非阻塞 I/O 操作的机制--尽管 JavaScript 是单线程处理的--当有可能的时候,它们会把操作转移到系统内核中去. 下面的图表显示了事件循环的 ...
- 事件循环机制 (Event Loop)
事件循环机制从整体上告诉了我们 JavaScript 代码的执行顺序Event Loop即事件循环,是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是我们经常使用 ...
- JavaScript中事件循环的理解 Event Loop
为了解决单线程运行阻塞问题,JavaScript用到了计算机系统的一种运行机制,这种机制就叫做事件循环(Event Loop) 事件循环(Event Loop) 在JavaScript中,所有的任务都 ...
- 彻底搞懂JS事件循环机制(event loop)
知识点: js异步实现 EventLoop.消息队列 宏任务 与 微任务 同步模式与异步模式 首先要确定 js是单线程语言,js在设计之初用作用户互动,以及操作DOM.这决定了它只能是单线程(例如多线 ...
- 八七、Node.js事件循环与多进程
nodejs事件循环与多进程 why 事件循环对于深入理解nodejs异步至关重要 fs, net,http,events 事件循环是企业面试中的最高频考题之一 能驾驭nodejs多进程是一名资深前端 ...
- 事件循环机制EventLoop
事件循环机制EventLoop Event Loop即事件循环,是解决javaScript单线程运行阻塞的一种机制. 一.EventLoop的相关概念 1.堆(Heap) 堆表示一大块非结构化的内存区 ...
最新文章
- JAVA 多线程实现包子铺(买包子,吃包子)
- Leangoo用户设置在哪里?
- 宝塔服务器环境好不好_服务器环境怎么搭建?(宝塔环境搭建教程)
- LINUX学习笔记高度浓缩版之一 :用户管理、启动过程、硬盘管理
- fedora,linux mint 命令行(终端)打开目录
- SDUTRescue The Princess(数学问题)
- 递归-递归的特点及基本代码演练
- 13.简述MYSQL的权限级别_MySQL权限级别
- android 怎么自定义任务栈,Android中的Activity详解--启动模式与任务栈
- 定时任务 Wpf.Quartz.Demo.3
- 查找你的幸运守护精灵
- 《on Java 中文版》读后感(《JAVA编程思想》的原作者)(JAVA 小虚竹)
- 利用Netica训练简易贝叶斯网络模型【教程】
- html代码中font是什么意思,HTML元素font标签的使用方法及作用
- 7系列FPGA数据手册:概述------中文翻译版
- 淘宝直播医美,颜值经济崛起,如何抢占流量风口
- Python matplotlib 堆叠图
- go get connectex: A connection attempt failed because the connected party did not properly respond
- 以太坊源码分析(10)CMD深入分析
- 分享了一篇文章:《格子出位nbsp;要你好看》
热门文章
- JetBrains 发布新款编程字体,提高编程效率、开源免费可商用!
- 雷达模拟器 SPx Radar Simulator
- 把mysql结果转换成数组实例
- 如何为机器视觉选择合适的采集卡
- 实时监测GPU的显存和显存清理小功能学习
- 中国科学院计算机在职研究生怎么样,中科大在职研究生好考吗,考进中科院的人很牛逼吗?...
- 阿里巴巴Java开发手册(纪念版 1.3.1)记录
- 域名交易谈判技巧:怎么给心仪域名还价?
- Detectron2入门:Ubuntu 20.04上安装Detectron2
- 对抗生成网络原理和作用