glib源码下载:http://ftp.gnome.org/pub/gnome/sources/glib/
glib帮助文档:https://developer.gnome.org/glib/
本节主要讲述线程间异步通信,实现原理就是用线程锁和队列实现的线程异步队列。
描述
通常你需要在不同的线程之间进行通信。 一般来说,不要通过共享内存来做这件事,而应该通过明确的消息传递。 这些消息对于多线程应用程序只是异步的,因为同步操作也可以在同一个线程中完成。异步队列是大多数其他GLib数据结构的一个例外,因为它们可以在多个线程中同时使用而不需要显式锁定,并且它们自带内置的引用计数。 这是因为异步队列的性质是它总是会被至少两个并发线程使用。
对于使用异步队列,您首先必须使用g_async_queue_new()创建一个。 GAsyncQueue结构是引用计数,使用g_async_queue_ref()和g_async_queue_unref()来管理您的引用。
想要发送消息到该队列的线程只需调用g_async_queue_push()将消息推送到队列。
预期来自异步队列消息的线程只需调用该队列的g_async_queue_pop()。 如果队列中没有可用的消息,那么线程现在处于休眠状态,直到消息到达。 该消息将从队列中移除并返回。 函数g_async_queue_try_pop()和g_async_queue_timeout_pop()可以用来检查消息的存在或者仅仅等待消息的一定时间。
几乎每个函数都有两个变量,一个锁定队列,另一个不锁定队列。 这样,您可以保持队列锁定(通过g_async_queue_lock()获取并通过g_async_queue_unlock())通过多个队列访问指令进行释放。 这对确保队列的完整性可能是必要的,但只有在真正需要时才能使用,因为如果使用不当,可能会使你的生活变得更加困难。 通常你只能使用锁定函数变体(那些没有_unlocked后缀的变体)。
在许多情况下,当您需要将工作分配到一组工作线程而不是手动使用GAsyncQueue时,使用GThreadPool可能会更方便。 GThreadPool在内部使用GAsyncQueue。
这个队列主要分为两套,一套是不使用线程队列锁时使用的函数,一套是使用线程锁时使用的函数,这两套不能混用,因为混用可能造成死锁。
不带锁相关函数
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 ()
下面是函数翻译
GAsyncQueue * g_async_queue_new ()
创建一个新的异步队列。
返回
一个新的GAsyncQueue。 使用g_async_queue_unref()释放
GAsyncQueue * g_async_queue_new_full ()
创建一个新的异步队列并设置一个destroy通知函数,该函数用于在队列在最终unref之后销毁时释放任何剩余的队列项。
参数
item_free_func
函数释放队列元素
返回
一个新的GAsyncQueue。 使用g_async_queue_unref()释放
从:2.16
GAsyncQueue * g_async_queue_ref ()
将异步队列的引用计数增加1。您不需要保持锁来调用此函数。
参数
queue
一个GAsyncQueue
返回
传入的队列(从2.6开始)
void g_async_queue_unref ()
将异步队列的引用计数减1
如果引用计数为0,则队列将被销毁并分配的内存将被释放。 所以你不能使用队列,因为它可能已经消失了。 你不需要保持锁来调用这个函数。
参数
queue
一个GAsyncQueue。
void g_async_queue_push ()
将数据推入队列。 数据不能为NULL。
参数
queue
一个GAsyncQueue
data
数据推入队列
void g_async_queue_push_sorted ()
使用func将数据插入队列以确定新的位置。
这个函数需要在推入新元素之前对队列进行排序,请参阅g_async_queue_sort()。
这个函数会在对队列进行排序之前锁定队列,并在完成时将其解锁。
有关func的示例,请参阅g_async_queue_sort()。
参数
queue
一个GAsyncQueue
data
将数据推入队列
func
GCompareDataFunc用于对队列进行排序
user_data
用户数据传递给func。
从:2.10
void g_async_queue_push_front ()
将项目推入队列。 项目不能为NULL。 与g_async_queue_push()不同的是,这个函数在队列中已经存在的项目之前压入新的项目,这样它将成为下一个从队列中弹出的项目。
参数
queue
一个GAsyncQueue
item
数据推入队列
由于:2.46
gboolean g_async_queue_remove ()
从队列中删除一个项目。
queue
一个GAsyncQueue
item
要从队列中删除的数据
返回
如果项目被移除,则为TRUE
从:2.46
gpointer g_async_queue_pop ()
从队列中弹出数据。 如果队列为空,则此功能会阻塞,直到数据可用。
参数
queue
一个GAsyncQueue
返回
来自队列的数据
gpointer g_async_queue_try_pop ()
试图从队列中弹出数据。 如果没有数据可用,则返回NULL。
参数
queue
一个GAsyncQueue
返回
来自队列的数据或NULL,当没有数据立即可用时。
gpointer g_async_queue_timeout_pop ()
从队列中弹出数据。 如果队列为空,则超时微秒或直到数据可用。
如果在超时之前没有收到数据,则返回NULL。
参数
queue
一个GAsyncQueue
timeout
等待的微秒数
返回
在超时之前没有收到数据时,队列中的数据或NULL。
gint g_async_queue_length ()
返回队列的长度。
实际上这个函数返回队列中数据项的数量减去等待线程的数量,所以负值表示等待线程,正值表示队列中可用的项。 返回值0可以表示队列中的n个条目和n个等待的线程。 这可能是由于队列锁定或调度造成的。
参数
queue
一个GAsyncQueue。
返回
队列的长度
void g_async_queue_sort ()
使用func对队列进行排序。
sort函数func传递队列的两个元素。 如果它们相等,它应该返回0,如果第一个元素应该在队列中更高,则返回负值;如果队列中第一个元素应该比第二个元素低,则返回正值。
这个函数会在对队列进行排序之前锁定队列,并在完成时将其解锁。
如果您正在排序优先级编号列表以确保最低优先级位于队列顶部,则可以使用:
gint32 id1;
gint32 id2;
id1 = GPOINTER_TO_INT (element1);
id2 = GPOINTER_TO_INT (element2);
return (id1 > id2 ? +1 : id1 == id2 ? 0 : -1);
参数
queue
一个GAsyncQueue
func
GCompareDataFunc用于对队列进行排序
user_data
用户数据传递给func
从:2.10
void g_async_queue_lock ()
获取队列的锁。 如果另一个线程已经持有该锁,则该呼叫将被阻塞,直到该锁可用。
调用g_async_queue_unlock()再次放下锁。
在按住锁的同时,您只能调用队列上的g_async_queue _ * _ unlocked()函数。 否则,可能会发生死锁。
参数
queue
一个GAsyncQueue
void g_async_queue_unlock ()
释放队列的锁定。
当你没有获得g_async_queue_lock()时调用这个函数会导致未定义的行为。
参数
queue
一个GAsyncQueue
void g_async_queue_ref_unlocked ()
从版本2.8开始,g_async_queue_ref_unlocked已被弃用,不应在新编写的代码中使用。
引用计数是自动完成的。 所以不管队列的锁,都可以使用g_async_queue_ref()。
将异步队列的引用计数增加1。
参数
queue
一个GAsyncQueue
void g_async_queue_unref_and_unlock ()
g_async_queue_unref_and_unlock从版本2.8开始已被弃用,不应该用在新编写的代码中。
引用计数是自动完成的。 所以不管队列的锁,都可以使用g_async_queue_unref()。
将异步队列的引用计数减1,并释放锁定。 这个函数必须在持有队列锁的时候被调用。 如果引用计数为0,则队列将被销毁并分配的内存将被释放。
参数
queue
一个GAsyncQueue
void g_async_queue_push_unlocked ()
将数据推入队列。 数据不能为NULL。
这个函数必须在持有队列锁的时候被调用。
参数
queue
一个GAsyncQueue
data
数据推入队列
void g_async_queue_push_sorted_unlocked ()
使用func将数据插入队列以确定新的位置。
sort函数func传递队列的两个元素。 如果它们相等,它应该返回0,如果第一个元素应该在队列中更高,则返回负值;如果队列中第一个元素应该比第二个元素低,则返回正值。
这个函数需要在推入新元素之前对队列进行排序,请参阅g_async_queue_sort()。
这个函数必须在持有队列锁的时候被调用。
有关func的示例,请参阅g_async_queue_sort()。
参数
queue
一个GAsyncQueue
data
将数据推入队列
func
GCompareDataFunc用于对队列进行排序
user_data
用户数据传递给func。
从:2.10
void g_async_queue_push_front_unlocked ()
将项目推入队列。 项目不能为NULL。 与g_async_queue_push_unlocked()相比,此函数将新项目推到队列中已有的项目之前,这样它将成为下一个从队列中弹出的项目。
这个函数必须在持有队列锁的时候被调用。
参数
queue
一个GAsyncQueue
item
数据推入队列
由于:2.46
gboolean g_async_queue_remove_unlocked ()
从队列中删除一个项目。
这个函数必须在持有队列锁的时候被调用。
参数
queue
一个GAsyncQueue
item
要从队列中删除的数据
返回
如果项目被移除,则为TRUE
由于:2.46
gpointer g_async_queue_pop_unlocked ()
从队列中弹出数据。 如果队列为空,则此功能会阻塞,直到数据可用。
这个函数必须在持有队列锁的时候被调用。
参数
queue
一个GAsyncQueue
返回
来自队列的数据。
gpointer g_async_queue_try_pop_unlocked ()
试图从队列中弹出数据。 如果没有数据可用,则返回NULL。
这个函数必须在持有队列锁的时候被调用。
参数
queue
一个GAsyncQueue
返回
来自队列的数据或NULL,当没有数据立即可用时。
gpointer g_async_queue_timeout_pop_unlocked ()
从队列中弹出数据。 如果队列为空,则超时微秒或直到数据可用。
如果在超时之前没有收到数据,则返回NULL。
这个函数必须在持有队列锁的时候被调用。
参数
queue
一个GAsyncQueue
timeout
等待的微秒数
返回
在超时之前没有收到数据时,队列中的数据或NULL。
gint g_async_queue_length_unlocked ()
返回队列的长度。
实际上这个函数返回队列中数据项的数量减去等待线程的数量,所以负值表示等待线程,正值表示队列中可用的项。 返回值0可以表示队列中的n个条目和n个等待的线程。 这可能是由于队列锁定或调度造成的。
这个函数必须在持有队列锁的时候被调用。
参数
queue
一个GAsyncQueue
返回
队列的长度。
void g_async_queue_sort_unlocked ()
使用func对队列进行排序。
sort函数func传递队列的两个元素。 如果它们相等,它应该返回0,如果第一个元素应该在队列中更高,则返回负值;如果队列中第一个元素应该比第二个元素低,则返回正值。
这个函数必须在持有队列锁的时候被调用。
参数
queue
一个GAsyncQueue
func
GCompareDataFunc用于对队列进行排序
user_data
用户数据传递给func
从:2.10
gpointer g_async_queue_timed_pop ()
g_async_queue_timed_pop已弃用,不应在新编写的代码中使用。
使用g_async_queue_timeout_pop()。
从队列中弹出数据。 如果队列为空,则阻塞直到end_time或直到数据可用。
如果在end_time之前没有收到数据,则返回NULL。
为了便于计算end_time,可以使用g_get_current_time()和g_time_val_add()的组合。
参数
queue
一个GAsyncQueue
end_time
一个GTimeVal,确定最后的时间
返回
在end_time之前未收到数据时,队列中的数据或NULL。
gpointer g_async_queue_timed_pop_unlocked ()
不推荐使用g_async_queue_timed_pop_unlocked,不应该在新编写的代码中使用。
使用g_async_queue_timeout_pop_unlocked()。
从队列中弹出数据。 如果队列为空,则阻塞直到end_time或直到数据可用。
如果在end_time之前没有收到数据,则返回NULL。
为了便于计算end_time,可以使用g_get_current_time()和g_time_val_add()的组合。
这个函数必须在持有队列锁的时候被调用。
参数
queue
一个GAsyncQueue
end_time
一个GTimeVal,确定最后的时间
返回
在end_time之前未收到数据时,队列中的数据或NULL。
下面是一个简单的例程:
#include <glib.h>#include <glib/gprintf.h>GAsyncQueue *async_queue = NULL;gpointer thread_func1 (gpointer data){ gint *usr_data; while(1) { g_printf ("%s in\n", __func__); g_async_queue_lock (async_queue); usr_data = (gint *)g_async_queue_pop_unlocked (async_queue); g_printf("%s pop: %d\n", __func__, *usr_data); g_free (usr_data); g_printf ("queue length %d\n", g_async_queue_length_unlocked (async_queue)); g_async_queue_unlock (async_queue); g_usleep (2000000); }}gpointer thread_func2 (gpointer data){ gint *tmp; gint count = 0; while(1) { g_printf ("%s in\n", __func__); g_async_queue_lock (async_queue); tmp = (gint *)g_new0(gint, 1); *tmp = count++; g_async_queue_push_unlocked (async_queue, tmp); g_printf("%s count: %d\n", __func__, *tmp); g_async_queue_unlock (async_queue); g_usleep (1000000); }}int main(int argc, char **argv){ g_printf ("%s in\n", __func__); GThread *gthread1 = NULL, *gthread2 = NULL; async_queue = g_async_queue_new (); gthread2 = g_thread_new ("func2", thread_func2, NULL); g_usleep (1000000); gthread1 = g_thread_new ("func1", thread_func1, NULL); g_thread_join (gthread1); g_thread_join (gthread2); g_printf ("%s out\n", __func__); return 0;}