函数

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 的值时,可能可以让菜单项的回调立即返回而不执行任何操作。然而,应避免这样做,因为用户随后会看到选择菜单项不会执行任何操作。此外,你会发现自己在整个代码中都添加了这些检查,因为用户无疑可以执行许多操作。相反,你可以使用以下技术

  1. 当主循环正在递归时,使用 gtk_widget_set_sensitive() 或模式对话框防止用户与元素进行交互。

  2. 在无法处理任意回调的情况下,避免在主循环中递归。相反,对代码进行构造,使其只需返回到主循环中,然后在有更多工作需要执行时再次调用循环即可。

返回值

类型: gint

当前线程中的主循环递归级别。