当前位置: 首页 > 工具软件 > GLib > 使用案例 >

linux - glib使用

洪飞龙
2023-12-01

简介

  1. 源码下载
  2. glib库是Linux平台下最常用的C语言函数库,它具有很好的可移植性和实用性
  3. 编译链接:gcc g_init.c pkg-config --libs --cflags glib-2.0 -o g_init
  4. 功能特色
    (1)gobject是glib的精粹,gobject是所有类的基类。signal在其中也是一大特色。
    (2)glib提供了动态数组、单/双向链表、哈希表、多叉树、平衡二叉树、字符串等常用容器,完全是面向对象设计的。
    (3)glib里提供了词法分析、markup语言解析、ini文件存取等功能
    (4)glib提供了一套跨平台的backtrace函数
    (5)实现了一套完整的log机制
    (6)glib提供了一些的手段定位内存问题
  5. 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;
}

事件源

  1. 事件源: Idle, Timeout, I/O 和 自定义的事件源
  2. 自定义事件源:将外部信号(事件)挂到程序中的指定主循环上,从而在 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;
}
 类似资料: