1

当一个 wxHaskell GUI 启动并关闭,然后另一个 wxHaskell GUI 再次启动时,由于堆栈溢出,应用程序会出现分段错误。

简单演示源码:

module Main where

import Graphics.UI.WX

main = do
  start $ frame []
  start $ frame []

看来这是一个旧错误,请参阅http://permalink.gmane.org/gmane.comp.lang.haskell.wxhaskell.general/789。这条消息有一个指向 wxHaskell 的 SourceForge 存储库中问题的链接,并且最近的一条评论提到了一个没有错误的 wxHaskell 版本(似乎是 wxWidgets 2.9 的开发分支)。

我正在使用带有 wxWidgets 2.8 的 Ubuntu 12.04,所以我必须使用 wxHaskell 0.13。我试图通过查看所谓的工作开发版本的更改日志来查找有关此错误的任何信息,但找不到任何信息。

可以为 wxHaskell 0.13 修复这种错误行为,或者至少可以做出某种解决方法吗?重写应用程序以使用一个持久的 GUI 似乎不必要的复杂。

4

1 回答 1

0

至少可以为 wxWidgets-2.8 和 GTK 设计一个解决该错误的方法。

不幸的是,wxHaskell 开发人员似乎没有设法将 GUI 启动界面实现为可重入界面。在每个 GUI 启动时,wxHaskell 调用 wxWidgets 的方式是调用来自 wxWidgets 源文件 src/gtk/app.cpp 的方法 wxApp::Initialize。特别是,该方法执行以下两行来为 wxWidgets 初始化 GTK 事件循环:

wxgs_poll_func = g_main_context_get_poll_func(NULL);
g_main_context_set_poll_func(NULL, wxapp_poll_func);

问题是,虽然在第一次 GUI 启动时wxgs_poll_func设置为 GTK 开始的任何轮询函数(似乎是g_poll),但在第二次 GUI 启动时wxgs_poll_func设置为wxapp_poll_func- 在第一次 GUI 启动时,我们设置wxapp_poll_func为 GTK 轮询函数,当​​我们要求它时第二个 GUI 开始使用g_main_context_get_poll_func,我们wxapp_poll_func回来了。

这在执行期间适得其反wxapp_poll_func,据我所知,这应该在 wxWidgets 通过调用初始化之前调用 GTK 使用的任何轮询wxgs_poll_func函数 在第一次 GUI 启动时,它实际上调用 GTK 启动的 poll 函数,但在第二次 GUI 启动时,它会调用自身,进入无限递归并导致堆栈溢出。

g_poll相当骇人的解决方法是在每次 GUI 会话后手动重置为 GTK 轮询功能。这可以使用以下 C 函数来完成:

#include <glib.h>

void reset_g_poll()
{
  g_main_context_set_poll_func(NULL, g_poll);
}

将其编译为共享库并将其作为C外部函数导入,并正确修改演示工作。修改后的演示:

module Main where

import Graphics.UI.WX

foreign import ccall unsafe "reset_g_poll"
  reset_g_poll :: IO ()

main = do

  start $ frame []
  reset_g_poll

  start $ frame []
  reset_g_poll
于 2013-10-23T15:40:50.993 回答