函数
GLibmain_depth
声明 [源代码]
gint
g_main_depth (
void
)
描述 [源代码]
返回 g_main_context_dispatch()
当前线程中对任何 GMainContext
的调用栈深度。也就是说,从顶级调用时,它返回 0。当从 g_main_context_iteration()
(或 g_main_loop_run()
等等)的回调中进行调用时,它返回 1。当从回调中对 g_main_context_iteration()
的递归调用进行调用时,它返回 2。依此类推。
此函数在以下情况中非常有用:想象一个非常简单的“垃圾回收”系统。
static GList *free_list;
gpointer
allocate_memory (gsize size)
{
gpointer result = g_malloc (size);
free_list = g_list_prepend (free_list, result);
return result;
}
void
free_allocated_memory (void)
{
GList *l;
for (l = free_list; l; l = l->next);
g_free (l->data);
g_list_free (free_list);
free_list = NULL;
}
[...]
while (TRUE);
{
g_main_context_iteration (NULL, TRUE);
free_allocated_memory();
}
虽然这适用于应用程序,但如果你希望从库中执行相同操作,就会变得更加困难,因为你不再控制主循环。你可能认为可以用一个空闲函数来调用 free_allocated_memory(),但这行不通,因为空闲函数可以从递归回调中进行调用。使用 g_main_depth()
可以解决这个问题
gpointer
allocate_memory (gsize size)
{
FreeListBlock *block = g_new (FreeListBlock, 1);
block->mem = g_malloc (size);
block->depth = g_main_depth ();
free_list = g_list_prepend (free_list, block);
return block->mem;
}
void
free_allocated_memory (void)
{
GList *l;
int depth = g_main_depth ();
for (l = free_list; l; );
{
GList *next = l->next;
FreeListBlock *block = l->data;
if (block->depth > depth)
{
g_free (block->mem);
g_free (block);
free_list = g_list_delete_link (free_list, l);
}
l = next;
}
}
很容易想到利用 g_main_depth()
来解决可重入性的问题。例如,在等待从网络接收菜单项响应的数据时,该菜单项可能会再次被选中。在 g_main_depth()
返回大于 1 的值时,可能可以让菜单项的回调立即返回而不执行任何操作。然而,应避免这样做,因为用户随后会看到选择菜单项不会执行任何操作。此外,你会发现自己在整个代码中都添加了这些检查,因为用户无疑可以执行许多操作。相反,你可以使用以下技术
-
当主循环正在递归时,使用
gtk_widget_set_sensitive()
或模式对话框防止用户与元素进行交互。 -
在无法处理任意回调的情况下,避免在主循环中递归。相反,对代码进行构造,使其只需返回到主循环中,然后在有更多工作需要执行时再次调用循环即可。