Pine Blog

GLIB用户指南-对核心应用的支持

1.概述

GLib对核心应用的支持包括事件循环、内存操作、线程操作、动态链接库的操作和出错处理与日志等。
glib

2.事件循环、内存操作、线程

下面代码演示了事件循环、内存操作、线程这三种功能的简单应用:

#include <glib.h>
static GMutex *mutex = NULL;
static gboolean t1_end = FALSE;
static gboolean t2_end = FALSE;
typedef struct _Arg Arg;
struct _Arg
{
    GMainLoop* loop;
    gint max;
};
void    run_1(Arg *arg)
{
    int i ;
    
    for(i=0; i<arg->max; i++)
    {
        if(g_mutex_trylock(mutex) == FALSE)
        {
            //g_print("%d : thread 2 locked the mutex \n", i);
            g_print("%d :线程2锁定了互斥对象\n", i);
            g_mutex_unlock(mutex);
        }
        else
        {
            g_usleep(10);
        }
    }
    t1_end = TRUE;
}
void    run_2(Arg *arg)
{
    int i;
    for(i=0; i<arg->max; i++)
    {
        if(g_mutex_trylock(mutex) == FALSE)
        {
            //g_print("%d : thread 1 locked mutex \n", i);
            g_print("%d :线程1锁定了互斥对象\n", i);
            g_mutex_unlock(mutex);
        }
        else
        {
            g_usleep(10);
        }
    }
    t2_end = TRUE;
}
void run_3(Arg *arg)
{
    for(;;)
    {
        if(t1_end && t2_end)
        {
            g_main_loop_quit(arg->loop);
            break;
        }
    }
}
int    main(int argc, char *argv[])
{
    GMainLoop *mloop;
    Arg *arg;
    
    if(!g_thread_supported())
        g_thread_init(NULL);
    mloop = g_main_loop_new(NULL, FALSE);
    
    arg = g_new(Arg, 1);
    arg->loop = mloop;
    arg->max = 11;
        
    mutex = g_mutex_new();
    g_thread_create(run_1, arg, TRUE, NULL);
    g_thread_create(run_2, arg, TRUE, NULL);
    g_thread_create(run_3, arg, TRUE, NULL);
    
    g_main_loop_run(mloop);
    g_print("线程3退出事件循环\n");
    g_mutex_free(mutex);
    g_print("释放互斥对象\n"); 
    g_free(arg);
    g_print("释放参数所用的内存\n");
}

Makefile文件如下:

CC = gcc
all:
    $(CC) `pkg-config --cflags --libs glib-2.0 gthread-2.0` loop.c -o loop    

下面为输出结果:
0 :线程1锁定了互斥对象 
1 :线程2锁定了互斥对象 
2 :线程1锁定了互斥对象 
3 :线程2锁定了互斥对象 
4 :线程1锁定了互斥对象 
5 :线程2锁定了互斥对象 
6 :线程1锁定了互斥对象 
7 :线程2锁定了互斥对象 
8 :线程1锁定了互斥对象 
9 :线程2锁定了互斥对象 
10 :线程1锁定了互斥对象 
线程3退出事件循环 
释放互斥对象 
释放参数所用的内存 

以上例程创建了三个线程,其中run_1和run_2操作互斥对象,run_3检索前两个线程是否结束,如结束的话,则执行g_main_loop_quit退出事件循环。由于线程的运行是不确定的,所以不一定每次都是这一输出结果。
首先,定义一个结构类型来保存创建的事件循环的对象指针和线程运行时的最多循环次数,一般情况下,如果为此数据结构来分配内存的话,用Arg arg = (Arg )malloc(sizeof(Arg));,释放时用free(arg);,这种传统的做法曾经让很多C语言的初学者头痛,尤其是需要多次操作的时 候,GLib中提供了类似的函数g_malloc和g_free,最好用的方法是其将g_malloc函数封装成了宏g_new,这个宏有两个参数,第一个是结构类型,第二个是要分配结构的数量,这段代码中只用到了一个Arg数据结构,所以是g_new(Arg, 1)。在程序结束时用g_free来释放。
在线程初始化时,首先是判断线程是否初始化的函数g_thread_supported,如果其返回FALSE则表明线程并未初始化,这时必须用g_thread_init来初始化,这是较明智的做法。
事件循环GMainLoop在用g_main_loop_new创建之后并不马上运行,用g_main_loop_run运行后,还要用 g_main_loop_quit退出,否则循环将一直运行下去,这两个函数的参数都是GMainLoop型的指针,在主函数中并未直接运行 g_main_loop_quit,而是把它放在线程的函数中了,这一点需读者注意。

3.随机数

GLib中包含了近二十种实用功能,从简单的字符处理到初学者很难理解的XML解析功能,这里介绍两种较简单的:随机数和计时。
下面代码演示如何产生1-100之间的随机整数和演示如何计算30000000次累加在计算时用的时间:

/* until.c 用来测试实用功能 */
#include <glib.h>
int    main(int argc, char *argv[])
{
    GRand *rand;
    GTimer *timer;
    
    gint n;
    gint i, j;
    gint x = 0;
    rand = g_rand_new();    //创建随机数对象
    for(n=0; n<20; n++)
    {    //产生随机数并显示出来
        g_print("%d\t",g_rand_int_range(rand,1,100));
    }
    g_print("\n");
    g_rand_free(rand);    //释放随机数对象
    //创建计时器
    timer = g_timer_new();
    g_timer_start(timer);//开始计时
    for(i=0; i<10000; i++)
        for(j=0; j<3000; j++)
            x++;//累计
    g_timer_stop(timer);//计时结束
    //输出计时结果
    g_print("%ld\tall:%.2f seconds was used!\n",x,g_timer_elapsed(timer,NULL));
}

Makefile文件内容如下:
CC = gcc all: $(CC) `pkg-config --cflags --libs glib-2.0 ` until.c -o until
输出结果:
48 95 95 99 90 24 90 29 78 4 53 87 1 86 7 93 57 88 75 4
30000000 all:1.47 seconds was used!

GLIB中的每个对象几乎都有一个或多个*_new函数来创建,计时器GTimer和随机器GRand也一样,也都有相对应的函数来结束对象的使用,如GTimer的g_timer_stop和GRand的g_rand_free。
这可能是GLIB实用功能中最简单的两种了,许多朋友会一目了然。我们还应注意到GLIB的代码风格和封装技巧是具有独到之处的,这种风格和技巧足以让一些自称简洁实用的SDK汗颜,学习掌握这一风格可能会让我们受益匪浅。

4.数据类型

GLib中定义了十几种常用的数据结构类型和它们的相关操作函数,下面是关于字符串类型的简单示例:

#include <glib.h>
int    main(int argc, char *argv[])
{
    GString *s;
    s = g_string_new("Hello");
    g_print("%s\n", s->str);
    s = g_string_append(s," World!");
    g_print("%s\n",s->str);
    s = g_string_erase(s,0,6);
    g_print("%s\n",s->str);
    s = g_string_prepend(s,"Also a ");
    g_print("%s\n",s->str);
    
    s = g_string_insert(s,6," Nice");
    g_print("%s\n",s->str);
}

Makefile文件如下:
    CC = gcc
all:
    $(CC) `pkg-config --cflags --libs glib-2.0 ` string.c -o str
        

下面是输出结果:
Hello
Hello World!
World!
Also a World!
Also a Nice World!

字符串在编程中出现频率之高,即使是初学者也很清楚,追加、删除和插入等常用操作理解后,还可以进一步了解掌握其它更复杂的操作。
GLib提供了一种内存块(GMemChunk)数据类型,它为分配等大的内存区提供了一种非常好用的操作方式,下面程序演示了内存块数据类型的简单用法:

#include <glib.h>
int    main(int argc, char *argv[])
{
    GMemChunk *chunk;    //定义内存块
    gchar *mem[10];    //定义指向原子的指针数组
    gint i, j;
    //创建内存块
    chunk = g_mem_chunk_new("Test MemChunk", 5, 50, G_ALLOC_AND_FREE);
                //名称,原子的长度, 内存块的长度,类型
    for(i=0; i<10; i++)
    {
        //创建对象
        //mem[i] = g_chunk_new(gchar, chunk);
        mem[i] = (gchar*)g_mem_chunk_alloc(chunk);
        for(j=0; j<5; j++)
        {
            mem[i][j] = 'A' + j;//为内存块中的指针赋值
        }
    }
    
    g_mem_chunk_print(chunk);    //显示内存块信息
    for(i=0; i<10; i++)
    {
        g_print("%s\t",mem[i]);//显示内存块中的内容
    }
    
    for(i=0; i<10; i++)
    {
        g_mem_chunk_free(chunk,mem[i]); //释放所有分配的内存
    }
    g_mem_chunk_destroy(chunk);
}

Makefile文件件如下:

CC = gcc
all:
    $(CC) `pkg-config --cflags --libs glib-2.0` data1.c -o data1

以下为输出结果:
GLib-INFO: Test MemChunk: 80 bytes using 2 mem areas
ABCDE    ABCDE    ABCDE    ABCDE    ABCDE    ABCDE    ABCDE    ABCDE    ABCDE    ABCDE

这里说明这一数据类型的原因是通过它可以他细体会内存分配这一运行时处理环节的应用之妙。
我们在程序中分配的是50字节的空间,而实际用的是80字节,由此可以看出其在分配内存时本身用到了部分内存空间。
从上面的示例代码中可以看出,在GLib中几乎所有的对象都是C语言的结构类型,一般命名以大写字母G开头的单词,如GList表示双向链表,所有与之相关 的操作函数都以小写的字母g加下划线加小写的单词加下划线开头,如以g_list_*开头的函数都是与这相关的操作函数,而且这些函数中的第一个参数多数 是此对象的指针。

GLIB中的数据类型在GLIB本身,尤其是GTK+中频繁用到,了解掌握这些数据类据类型的用法是非常必要的,这对进一步灵活开发GTK+程序来说是关键一环,而且是对大学中的《数据结构》一科的很好回顾。
在下一篇GOBJECT对象系统中将详细介绍GLIB中最重要的组成部分GOBJECT系统,希望这一由C语言组建的单继承的对象系统会帮助你走进GTK+的世界。

文章转载自:https://blog.csdn.net/l197803/article/details/138244885?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EYuanLiJiHua%7EPosition-2-138244885-blog-52932358.235%5Ev43%5Epc_blog_bottom_relevance_base2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EYuanLiJiHua%7EPosition-2-138244885-blog-52932358.235%5Ev43%5Epc_blog_bottom_relevance_base2&utm_relevant_index=5,如有问题请联系删除。

未经允许不得转载:Pine Blog » GLIB用户指南-对核心应用的支持

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

Pine Blog
Anywhere, Anytime
E-mail:59054872@qq.com
苏ICP备15059480号-1