简介
- 源码下载
- glib库是Linux平台下最常用的C语言函数库,它具有很好的可移植性和实用性
- 编译链接:gcc g_init.c
pkg-config --libs --cflags glib-2.0
-o g_init - 功能特色
(1)gobject是glib的精粹,gobject是所有类的基类。signal在其中也是一大特色。
(2)glib提供了动态数组、单/双向链表、哈希表、多叉树、平衡二叉树、字符串等常用容器,完全是面向对象设计的。
(3)glib里提供了词法分析、markup语言解析、ini文件存取等功能
(4)glib提供了一套跨平台的backtrace函数
(5)实现了一套完整的log机制
(6)glib提供了一些的手段定位内存问题 - GLib 实现了一个功能强大的事件循环分发处理机制.
(1)被抽象成 GMainLoop,用于循环处理事件源上的事件,每个 GMainLoop 都工作在指定的 GMainContext 上。
(2)事件源在 GLib 中则被抽象成了 GSource。在 GMainContext 中有一个 GSource 列表。
(3)GLib 内部定义实现了三种类型的事件源,分别是 Idle, Timeout 和 I/O。同时也支持创建自定义的事件源。
命令行参数解析
#include <glib.h>
gboolean cmd_arg_show_version = FALSE;
gint cmd_arg_product = 0;
gchar *cmd_arg_name = NULL;
static GOptionEntry entries[] = {
{ "version", 'v', 0, G_OPTION_ARG_NONE, &cmd_arg_show_version, "Show version", NULL },
{ "product", 'p', 0, G_OPTION_ARG_INT, &cmd_arg_product, "product mode", NULL },
{ "name", 'n', 0, G_OPTION_ARG_STRING, &cmd_arg_name, "product name", NULL },
{ NULL }
};
typedef struct _glib_context {
GMainLoop *main_loop;
} glib_context_t;
static glib_context_t *glib_context = NULL;
int main(int argc, char *argv[])
{
GError *error = NULL;
GOptionContext *context = g_option_context_new("- argument");
g_option_context_add_main_entries(context, entries, NULL);
if (!g_option_context_parse(context, &argc, &argv, &error)) {
g_printerr("option parsing failed: %s\n", error->message);
g_option_context_free(context);
exit(EXIT_FAILURE);
}
g_option_context_free(context);
if (cmd_arg_show_version) {
g_print("%s\n", "v1.0");
exit(EXIT_SUCCESS);
}
glib_context = (glib_context_t *)g_malloc0(sizeof(glib_context_t));
glib_context->main_loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(glib_context->main_loop);
if (glib_context->main_loop) {
g_main_loop_unref(glib_context->main_loop);
glib_context->main_loop = NULL;
}
g_free(glib_context);
glib_context = NULL;
return 0;
}
事件源
- 事件源: Idle, Timeout, I/O 和 自定义的事件源
- 自定义事件源:将外部信号(事件)挂到程序中的指定主循环上,从而在 g_main_loop_run 中可以响应这些事件
(1)自定义的事件源继承 GSource 的结构体,即自定义事件源的结构体 的第一个成员是 GSource 结构体, 其后便可放置程序所需数据
[1] sample: struct Test_Source { GSource _source; gchar userdata[256]; }
(2)实现事件源所规定的接口,它们包含于 GSourceFuncs 结构体中
[1] 主要为 prepare, check, dispatch, finalize 等事件处理函数(回调函数)
(3)g_source_new 构造一个新的事件源, g_source_attach 将新的事件源添加到主循环上下文中
#include <glib.h>
#include <glib/gstdio.h>
#include <glib/gprintf.h>
gboolean cmd_arg_show_version = FALSE;
gint cmd_arg_product = 0;
gchar *cmd_arg_name = NULL;
static GOptionEntry entries[] = {
{ "version", 'v', 0, G_OPTION_ARG_NONE, &cmd_arg_show_version, "Show version", NULL },
{ "product", 'p', 0, G_OPTION_ARG_INT, &cmd_arg_product, "product mode", NULL },
{ "name", 'n', 0, G_OPTION_ARG_STRING, &cmd_arg_name, "product name", NULL },
{ NULL }
};
typedef struct _glib_context {
GMainLoop *main_loop;
GMainContext *context;
} glib_context_t;
static gint should_exit = 0;
static glib_context_t *glib_context = NULL;
static void sig_int_handler(int signo G_GNUC_UNUSED)
{
should_exit++;
if (should_exit == 1) {
if (g_main_loop_is_running(glib_context->main_loop)) {
g_main_loop_quit(glib_context->main_loop);
g_printf("\n\n sig_int_handler exit ***\n");
}
}
}
void OptionContextParse(int argc, char *argv[])
{
GError *error = NULL;
GOptionContext *context = g_option_context_new("- argument");
g_option_context_add_main_entries(context, entries, NULL);
if (!g_option_context_parse(context, &argc, &argv, &error)) {
g_printerr("option parsing failed: %s\n", error->message);
g_option_context_free(context);
exit(EXIT_FAILURE);
}
g_option_context_free(context);
if (cmd_arg_show_version) {
g_print("%s\n", "v1.0");
exit(EXIT_SUCCESS);
}
if (cmd_arg_name) {
g_print("cmd_arg_name: %s\n", cmd_arg_name);
exit(EXIT_SUCCESS);
}
}
typedef struct _MySource
{
GSource source;
gchar text[256];
} MySource;
// 判断其返回值以确定各事件源是否作好准备,返回false后会调用check,返回true会执行dispatch函数
static gboolean prepare(GSource *source, gint *timeout)
{
*timeout = 1000; /* set time interval one msecond */
g_printf("prepare ***\n");
return FALSE;
}
static gboolean check(GSource *source)
{
g_printf("check ***\n");
static int i = 0;
i++;
if (i % 2 == 0)
return FALSE;
else
return TRUE;
}
static gboolean dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
{
MySource *mysource = (MySource *)source;
g_print("dispatch: %s\n", mysource->text);
return TRUE;
}
static void finalize(GSource *source)
{
MySource *mysource = (MySource *)source;
g_print("finalize: %s\n", mysource->text);
}
GSourceFuncs source_funcs = {prepare, check, dispatch, finalize};
void glib_self_defined_Source_process(glib_context_t *glib_context)
{
glib_context->context = g_main_loop_get_context(glib_context->main_loop);
GSource *source = g_source_new(&source_funcs, sizeof(MySource)); // sizeof() 是自定义的长度
g_sprintf(((MySource *)source)->text, "glib_Source_process!");
// context 如果为局部参数会crash,函数完成后会被销毁,context变为野指针
g_source_attach(source, glib_context->context);
g_source_unref(source);
}
// 返回值:TRUE,主事件循环空闲时重复被执行;
// 返回值:FALSE,执行一次后,被主事件循环从事件源中移除
static gboolean idle_func(gpointer data)
{
static int i = 0;
i++;
if (i % 5 != 0)
g_print ("idle_func %d, data %s.\n", i, (gchar *)data);
else
return FALSE;
return TRUE;
}
static gboolean timeout_func(gpointer data)
{
static int i = 0;
i++;
if (i % 5 != 0)
g_print ("timeout_func %d\n", i);
else
return FALSE;
return TRUE;
}
gboolean io_watch(GIOChannel *channel, GIOCondition condition, gpointer data)
{
gsize len = 0;
gchar *buffer = NULL;
g_io_channel_read_line(channel, &buffer, &len, NULL, NULL);
if(len > 0)
g_print("io_watch: %ld, buffer:%s.\n", len, buffer);
g_free(buffer);
return TRUE;
}
int main(int argc, char *argv[])
{
signal(SIGINT, sig_int_handler);
OptionContextParse(argc, argv);
glib_context = (glib_context_t *)g_malloc0(sizeof(glib_context_t));
/* GMainLoop数据类型代表了一个主事件循环, 通过g_main_loop_new()来创建GMainLoop对象,
在添加完初始事件源后执行g_main_loop_run(),主循环将持续不断的检查每个事件源产生的新事件,然后分发它们,
直到处理来自某个事件源的事件的时候触发了g_main_loop_quit()调用退出主循环为止。*/
glib_context->main_loop = g_main_loop_new(NULL, FALSE);
if (cmd_arg_product == 1)
glib_self_defined_Source_process(glib_context);
if (cmd_arg_product == 2)
g_idle_add(idle_func, "idle_func!");
if (cmd_arg_product == 3)
g_timeout_add(2, timeout_func, glib_context->main_loop);
guint watch_id;
gint fd = 0;
GIOChannel* channel = NULL;
if (cmd_arg_product == 4) {
channel = g_io_channel_unix_new(1);
if(channel) {
watch_id = g_io_add_watch(channel, G_IO_IN, io_watch, NULL);
g_io_channel_unref(channel);
}
}
g_main_loop_run(glib_context->main_loop);
if (cmd_arg_product == 4) {
// 退出事件循环
g_source_remove (watch_id);
// 释放 IO_Channel,内部调用了 g_io_channel_shutdown
//g_io_channel_unref (channel);
}
if (glib_context->main_loop) {
g_main_loop_unref(glib_context->main_loop);
glib_context->main_loop = NULL;
}
g_free(glib_context);
glib_context = NULL;
g_printf("main exit ***\n");
return 0;
}