5_05_GLib库入门与实践_异步队列

简介

在数据类型里面介绍过双端队列,双端队列没有线程和锁的概念,需要调用者自行保证数据同步性,本章要介绍的是异步队列,本身具有多线程同步特性,非常方便使用。

数据结构

异步队列的数据结构不透明,只可以整体使用它,无法单独引用其内部的成员。

typedef struct _GAsyncQueue GAsyncQueue;

函数列表

GAsyncQueue * 	g_async_queue_new ()
GAsyncQueue * 	g_async_queue_new_full ()
GAsyncQueue * 	g_async_queue_ref ()
void 	g_async_queue_unref ()
void 	g_async_queue_push ()
void 	g_async_queue_push_sorted ()
void 	g_async_queue_push_front ()
gboolean 	g_async_queue_remove ()
gpointer 	g_async_queue_pop ()
gpointer 	g_async_queue_try_pop ()
gpointer 	g_async_queue_timeout_pop ()
gint 	g_async_queue_length ()
void 	g_async_queue_sort ()
void 	g_async_queue_lock ()
void 	g_async_queue_unlock ()
void 	g_async_queue_ref_unlocked ()
void 	g_async_queue_unref_and_unlock ()
void 	g_async_queue_push_unlocked ()
void 	g_async_queue_push_sorted_unlocked ()
void 	g_async_queue_push_front_unlocked ()
gboolean 	g_async_queue_remove_unlocked ()
gpointer 	g_async_queue_pop_unlocked ()
gpointer 	g_async_queue_try_pop_unlocked ()
gpointer 	g_async_queue_timeout_pop_unlocked ()
gint 	g_async_queue_length_unlocked ()
void 	g_async_queue_sort_unlocked ()
gpointer 	g_async_queue_timed_pop ()
gpointer 	g_async_queue_timed_pop_unlocked ()

函数功能分类

创建

// 最简单的异步队列创建函数
GAsyncQueue * 	g_async_queue_new ()
// 带节点释放函数的异步队列创建函数
GAsyncQueue * 	g_async_queue_new_full ()

加解锁

// 异步队列的函数大多有两个版本,一个是带锁版本,一个是不带锁版本
// 如果使用的是不带锁版本,需要先对异步队列lock,使其获得锁,才可以调用无锁函数,执行完之后,再解锁
void 	g_async_queue_lock ()
void 	g_async_queue_unlock ()

入队列

// 最常用的入队列操作函数
void 	g_async_queue_push ()
// 将数据入队列到指定位置,此函数要求队列原来就是有序的,执行完入队列操作后,队列仍保持有序
void 	g_async_queue_push_sorted ()
// 将数据入队列到队列最开始位置
void 	g_async_queue_push_front ()
// 下面三个是入队列的无锁操作函数,和上面三个的作用相同,但需要配合g_async_queue_lock和g_async_queue_unlock使用。
void 	g_async_queue_push_unlocked ()
void 	g_async_queue_push_sorted_unlocked ()
void 	g_async_queue_push_front_unlocked ()

出队列

// 最常用的出队列操作函数
gpointer 	g_async_queue_pop ()
// 尝试出队列,此函数不会阻塞,队列中没有数据会立即返回
gpointer 	g_async_queue_try_pop ()
// 尝试出队列,阻塞指定时间,超时后返回
gpointer 	g_async_queue_timeout_pop ()
// 下面三个是出队列的无锁操作函数,和上面三个的作用相同,但需要配合g_async_queue_lock和g_async_queue_unlock使用。
gpointer 	g_async_queue_pop_unlocked ()
gpointer 	g_async_queue_try_pop_unlocked ()
gpointer 	g_async_queue_timeout_pop_unlocked ()

排序

// 队列内数据排序,有锁和无锁两个版本
void 	g_async_queue_sort ()
void 	g_async_queue_sort_unlocked ()

测长

// 返回队列长度,有锁和无锁两个版本
gint 	g_async_queue_length ()
gint 	g_async_queue_length_unlocked ()

移除

// 将一个元素从队列移除,有锁和无锁两个版本
gboolean 	g_async_queue_remove ()
gboolean 	g_async_queue_remove_unlocked ()

引用解引用

// GLib特有的引用和解引用函数,有锁和无锁两个版本
GAsyncQueue * 	g_async_queue_ref ()
void 	g_async_queue_unref ()
void 	g_async_queue_ref_unlocked ()
void 	g_async_queue_unref_and_unlock ()

函数功能说明及综合演示

出队列

g_async_queue_pop函数,如果队列中没有数据,则此接口一直阻塞。

举例验证:push线程延迟2秒向队列发送数据,则pop线程会阻塞2秒,直到队列中有数据。
演示程序见下:
源码见glib_examples\glib_async_queue\glib_async_queue_pop

#include <glib.h>

static gpointer test_aqueue_push_func(gpointer data)
{
    GAsyncQueue *aqueue = NULL;

    g_print("%s \n", __FUNCTION__);
    g_print("delay 2 seconds to push data \n");
    g_usleep(2*1000*1000);

    aqueue = (GAsyncQueue *)data;

    g_async_queue_push(aqueue, GINT_TO_POINTER(99));

    return NULL;
}

static gpointer test_aqueue_pop_func(gpointer data)
{
    gpointer val = NULL;
    GAsyncQueue *aqueue = NULL;
    g_print("%s \n", __FUNCTION__);

    aqueue = (GAsyncQueue *)data;

    val = g_async_queue_pop(aqueue);
    g_print("val: %d \n", GPOINTER_TO_INT(val));

    return NULL;
}

gint main(gint argc, gchar **argv)
{
    GThread *thd_push, *thd_pop;
    GAsyncQueue *aqueue = NULL;

    aqueue = g_async_queue_new();

    thd_push = g_thread_new("thd_push", test_aqueue_push_func, aqueue);
    thd_pop  = g_thread_new("thd_pop", test_aqueue_pop_func, aqueue);

    g_thread_join(thd_push);
    g_thread_join(thd_pop);

    g_async_queue_unref(aqueue);

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_async_queue_pop 
test_aqueue_pop_func 
test_aqueue_push_func 
delay 2 seconds to push data 
val: 99 
[root@centos7_6 build]# ./glib_async_queue_pop 
test_aqueue_push_func 
delay 2 seconds to push data 
test_aqueue_pop_func 
val: 99

无论是pop线程还是push线程先执行,都是等2秒之后才能取到数据,在这2秒内pop线程阻塞。

异步队列锁

下列函数允许调用者自己处理异步队列的锁。

g_async_queue_lock
g_async_queue_unlock
g_async_queue_push_unlocked
g_async_queue_pop_unlocked

下面举例演示一下上述函数的用法。
源码见glib_examples\glib_async_queue\glib_async_queue_locks

#include <glib.h>

static gpointer test_aqueue_push_func(gpointer data)
{
    GAsyncQueue *aqueue = NULL;

    g_print("%s \n", __FUNCTION__);

    aqueue = (GAsyncQueue *)data;

    g_async_queue_lock(aqueue);
    g_async_queue_push_unlocked(aqueue, GINT_TO_POINTER(99));
    g_async_queue_unlock(aqueue);

    return NULL;
}

static gpointer test_aqueue_pop_func(gpointer data)
{
    gpointer val = NULL;
    GAsyncQueue *aqueue = NULL;
    g_print("%s \n", __FUNCTION__);

    aqueue = (GAsyncQueue *)data;

    g_async_queue_lock(aqueue);
    val = g_async_queue_pop_unlocked(aqueue);
    g_async_queue_unlock(aqueue);

    g_print("val: %d \n", GPOINTER_TO_INT(val));

    return NULL;
}

gint main(gint argc, gchar **argv)
{
    GThread *thd_push, *thd_pop;
    GAsyncQueue *aqueue = NULL;

    aqueue = g_async_queue_new();

    thd_push = g_thread_new("thd_push", test_aqueue_push_func, aqueue);
    thd_pop  = g_thread_new("thd_pop", test_aqueue_pop_func, aqueue);

    g_thread_join(thd_push);
    g_thread_join(thd_pop);

    g_async_queue_unref(aqueue);

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_async_queue_locks
test_aqueue_push_func 
test_aqueue_pop_func 
val: 99 
[root@centos7_6 build]# ./glib_async_queue_locks
test_aqueue_pop_func 
test_aqueue_push_func 
val: 99
尝试出队列

g_async_queue_try_pop尝试从队列中取出一个元素,如果队列中有数据,则取出,如果队列中无数据,则返回空,此接口不阻塞。

源码见glib_examples\glib_async_queue\glib_async_queue_try_pop

#include <glib.h>

static gpointer test_aqueue_push_func(gpointer data)
{
    GAsyncQueue *aqueue = NULL;

    g_print("%s \n", __FUNCTION__);
    g_print("delay 1 seconds to push data \n");
    g_usleep(1*1000*1000);

    aqueue = (GAsyncQueue *)data;

    g_async_queue_push(aqueue, GINT_TO_POINTER(99));

    return NULL;
}

static gpointer test_aqueue_pop_func(gpointer data)
{
    gpointer val = NULL;
    GAsyncQueue *aqueue = NULL;
    g_print("%s \n", __FUNCTION__);

    aqueue = (GAsyncQueue *)data;

    val = g_async_queue_try_pop(aqueue);
    g_print("val: %d \n", GPOINTER_TO_INT(val));

    g_print("delay 2 seconds to pop data \n");
    g_usleep(2*1000*1000);

    val = g_async_queue_try_pop(aqueue);
    g_print("val: %d \n", GPOINTER_TO_INT(val));

    val = g_async_queue_try_pop(aqueue);
    g_print("val: %d \n", GPOINTER_TO_INT(val));

    return NULL;
}

gint main(gint argc, gchar **argv)
{
    GThread *thd_push, *thd_pop;
    GAsyncQueue *aqueue = NULL;

    aqueue = g_async_queue_new();

    thd_push = g_thread_new("thd_push", test_aqueue_push_func, aqueue);
    thd_pop  = g_thread_new("thd_pop", test_aqueue_pop_func, aqueue);

    g_thread_join(thd_push);
    g_thread_join(thd_pop);

    g_async_queue_unref(aqueue);

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_async_queue_try_pop 
test_aqueue_pop_func 
val: 0 
delay 2 seconds to pop data 
test_aqueue_push_func 
delay 1 seconds to push data 
val: 99 
val: 0
尝试出队列无锁版本

g_async_queue_try_pop_unlocked与g_async_queue_try_pop类似,需要自己处理锁。
下面是示例函数:
源码见glib_examples\glib_async_queue\glib_async_queue_try_pop_unlocked

#include <glib.h>

static gpointer test_aqueue_push_func(gpointer data)
{
    GAsyncQueue *aqueue = NULL;

    g_print("%s \n", __FUNCTION__);
    g_print("delay 1 seconds to push data \n");
    g_usleep(1*1000*1000);

    aqueue = (GAsyncQueue *)data;

    g_async_queue_lock(aqueue);
    g_async_queue_push_unlocked(aqueue, GINT_TO_POINTER(99));
    g_async_queue_unlock(aqueue);

    return NULL;
}

static gpointer test_aqueue_pop_func(gpointer data)
{
    gpointer val = NULL;
    GAsyncQueue *aqueue = NULL;
    g_print("%s \n", __FUNCTION__);

    aqueue = (GAsyncQueue *)data;

    g_async_queue_lock(aqueue);
    val = g_async_queue_try_pop_unlocked(aqueue);
    g_print("val: %d \n", GPOINTER_TO_INT(val));
    g_async_queue_unlock(aqueue);

    g_print("delay 2 seconds to pop data \n");
    g_usleep(2*1000*1000);

    g_async_queue_lock(aqueue);
    val = g_async_queue_try_pop_unlocked(aqueue);
    g_print("val: %d \n", GPOINTER_TO_INT(val));
    g_async_queue_unlock(aqueue);

    g_async_queue_lock(aqueue);
    val = g_async_queue_try_pop_unlocked(aqueue);
    g_print("val: %d \n", GPOINTER_TO_INT(val));
    g_async_queue_unlock(aqueue);

    return NULL;
}

gint main(gint argc, gchar **argv)
{
    GThread *thd_push, *thd_pop;
    GAsyncQueue *aqueue = NULL;

    aqueue = g_async_queue_new();

    thd_push = g_thread_new("thd_push", test_aqueue_push_func, aqueue);
    thd_pop  = g_thread_new("thd_pop", test_aqueue_pop_func, aqueue);

    g_thread_join(thd_push);
    g_thread_join(thd_pop);

    g_async_queue_unref(aqueue);

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_async_queue_try_pop_unlocked
test_aqueue_push_func 
delay 1 seconds to push data 
test_aqueue_pop_func 
val: 0 
delay 2 seconds to pop data 
val: 99 
val: 0

可以看到三次try_pop均立即返回,当队列中没有数据时,返回值为空。

超时

g_async_queue_timeout_pop,从异步队列中取数据,阻塞指定时间,超时则退出,返回值为空。
如果队列中有数据,则本函数立即返回。
超时时间为微秒Microsecond(1Second=1*1000Millisecond=1*1000*1000Microsecond)。

下面是演示程序:
源码见glib_examples\glib_async_queue\glib_async_queue_timed_pop

#include <glib.h>

static gpointer test_aqueue_push_func(gpointer data)
{
    GAsyncQueue *aqueue = NULL;

    g_print("%s \n", __FUNCTION__);
    g_print("delay 2 seconds to push data \n");
    g_usleep(2*1000*1000);

    aqueue = (GAsyncQueue *)data;

    g_async_queue_push(aqueue, GINT_TO_POINTER(99));

    return NULL;
}

static gpointer test_aqueue_pop_func(gpointer data)
{
    gpointer val = NULL;
    guint64 timeout = 0;
    GAsyncQueue *aqueue = NULL;
    g_print("%s \n", __FUNCTION__);

    aqueue = (GAsyncQueue *)data;


    timeout = 1*1000*1000;
    val = g_async_queue_timeout_pop(aqueue, timeout);
    g_print("val: %d \n", GPOINTER_TO_INT(val));

    g_print("delay 2 seconds to pop data again \n");
    g_usleep(2*1000*1000);
    val = g_async_queue_try_pop(aqueue);
    g_print("val: %d \n", GPOINTER_TO_INT(val));

    return NULL;
}

gint main(gint argc, gchar **argv)
{
    GThread *thd_push, *thd_pop;
    GAsyncQueue *aqueue = NULL;

    aqueue = g_async_queue_new();

    thd_push = g_thread_new("thd_push", test_aqueue_push_func, aqueue);
    thd_pop  = g_thread_new("thd_pop", test_aqueue_pop_func, aqueue);

    g_thread_join(thd_push);
    g_thread_join(thd_pop);

    g_async_queue_unref(aqueue);

    return 0;
}

运行结果:

[root@centos7_6 build]# ./glib_async_queue_timed_pop
test_aqueue_push_func 
delay 2 seconds to push data 
test_aqueue_pop_func 
val: 0 
delay 2 seconds to pop data again 
val: 99
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值