为什么我会收到一个分段错误(qtruby)?

3

我在访问一个类变量(Qt::Action 数组)时遇到了分段错误的问题,我一直在尝试精简代码以复现这个问题:

#!/usr/bin/ruby

require 'Qt4'
require 'rufus/scheduler'

app = Qt::Application.new(ARGV)

class ManagerWidget < Qt::Widget
    signals 'changed(int)'

    def initialize
        super(nil)

        max_index = 2
        next_index = 0

        scheduler = Rufus::Scheduler.start_new
        scheduler.every '10s' do
            emit changed(next_index)
            if next_index < max_index - 1
                next_index += 1
            else
                next_index = 0
            end
        end
    end
end

class Tray < Qt::Widget
    def initialize
        super(nil)

        tray = Qt::SystemTrayIcon.new
        manager_widget = ManagerWidget.new
        menu = Qt::Menu.new

        tray_icon = Qt::Icon.new("./icons/Gnome-Preferences-Desktop-Wallpaper-64.png")

        actions = []
        manager_widget.connect(SIGNAL('changed(int)')) do |i|
            puts "changed #{i}"
            actions[i].text = '...' if actions && actions[i]
        end

        2.times do |i|
            sub_menu = Qt::Menu.new("#{i + 1}")
            actions[i] = sub_menu.add_action('x')
            menu.add_menu(sub_menu)
        end

        tray.icon = tray_icon
        tray.context_menu = menu

        tray.show
    end
end

Tray.new
app.exec

上面的代码输出:
"sni-qt/12147" WARN  14:35:48.326 void StatusNotifierItemFactory::connectToSnw() Invalid interface to SNW_SERVICE 
changed 0
changed 1
changed 0
changed 1
changed 0
changed 1
changed 0
changed 1
./min-code-example.rb:42: [BUG] Segmentation fault
ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux]
[... snipped due to character limits on posting ...]
[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html

Aborted (core dumped)
Failed (134)

似乎需要使用子菜单来触发此问题 - 至少将操作添加到托盘菜单本身可以运行相当长的时间而没有问题(我让它运行了比上面的代码出错所需的时间长10倍以上)。
Ruby版本:ruby 1.9.3p0 (2011-10-30 revision 33570) [x86_64-linux] Qt版本:4.8.1 绑定版本:qtbindings (4.8.3.0) Linux版本:Ubuntu 12.04 另一个奇怪的行为是,puts调用的输出有时会立即显示在控制台中,而其他时候只有在我将鼠标悬停在托盘图标上时才会打印出来。
我甚至不确定从何处开始追踪这个问题,因此非常感谢您提供的任何意见。
更新:由于无法进一步进行,我已经放置了一段时间。我试图重新开始解决这个问题,但我仍然遇到了同样的问题。我深入研究了一下问题,因为它说“missing_method”,所以我首先打印类来确保我确实在查看Qt :: Action(我是),然后查看哪些方法根据actions [0] .methods 可用。
[:setShortcut, :shortcut=, :qobject_cast, :inspect, :pretty_print, :className,
:class_name, :inherits, :findChildren, :find_children, :findChild, :find_child,
:connect, :method_missing, :const_missing, :dispose, :isDisposed, :disposed?,
:qVariantValue, :qVariantFromValue, :**, :+, :~, :-@, :-, :*, :/, :%, :>>,
:<<, :&, :^, :|, :<, :<=, :>, :>=, :==, :is_a?, :kind_of?, :methods,
:protected_methods, :public_methods, :singleton_methods, :qDebug, :qFatal,
:qWarning, :SIGNAL, :SLOT, :emit, :QT_TR_NOOP, :QT_TRANSLATE_NOOP, :nil?, :===,
:=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup,
:initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust,
:untrusted?, :trust, :freeze, :frozen?, :to_s, :private_methods,
:instance_variables, :instance_variable_get, :instance_variable_set,
:instance_variable_defined?, :instance_of?, :tap, :send, :public_send,
:respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method,
:define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=,
:instance_eval, :instance_exec, :__send__, :__id__, "blockSignals", "children",
"connect", "deleteLater", "disconnect", "dumpObjectInfo", "dumpObjectTree",
"dynamicPropertyNames", "event", "eventFilter", "inherits", "installEventFilter",
"widgetType?", "killTimer", "metaObject", "moveToThread", "objectName", "parent",
"property", "qt_metacall", "qt_metacast", "removeEventFilter", "objectName=",
"parent=", "setProperty", "setUserData", "signalsBlocked", "startTimer",
"thread", "userData", "actionGroup", "activate", "associatedGraphicsWidgets",
"associatedWidgets", "autoRepeat", "data", "font", "hover", "icon", "iconText",
"checkable?", "checked?", "enabled?", "iconVisibleInMenu?", "separator?",
"visible?", "menu", "menuRole", "parentWidget", "priority", "actionGroup=",
"autoRepeat=", "checkable=", "checked=", "data=", "disabled=", "enabled=",
"font=", "icon=", "iconText=", "iconVisibleInMenu=", "menu=", "menuRole=",
"priority=", "separator=", "shortcut=", "shortcutContext=", "shortcuts=",
"softKeyRole=", "statusTip=", "text=", "toolTip=", "visible=", "whatsThis=",
"shortcut", "shortcutContext", "shortcuts", "showStatusText", "softKeyRole",
"statusTip", "text", "toggle", "toolTip", "trigger", "whatsThis"]

在这种情况下,我尝试执行actions[0].enabled = true时发生了段错误,据我理解(从底部第6行开始,enabled=),这也在输出中。我还尝试过setEnabled(true)set_enabled(true)和其他我能想到的任何方法。
即使在最初将操作放入数组的循环内部执行inspect操作也会导致段错误。我真的不知道出了什么问题。
编辑:针对使用QTimer的建议,我尝试了一下,但仍然遇到了同样的问题。目前的代码比上面列出的要复杂得多,因此我将在此处编写一些快速的伪代码来说明流程:
def init_tray
    actions = []
    2.times do |i|
        actions[i] = ... # init and add to systray, store reference in array
    end
    update = Proc.new do |i|
        actions[i].setText('...') # update the text on one of the actions defined above
    end
    listener = ... # create a listener that can be called by Manager on certain events - will call the update Proc among other things.
    manager = Manager.new(..., listener)
end

调用Manager.new初始化该对象并在最后调用监听器以进行状态更改,这反过来调用update Proc,该Proc访问actions数组。此时应该都在同一个线程中,除了实际创建Qt::Action的操作外,这些行都不依赖于QT。我已经删除了Rufus调度并使用QTimer代替,但它根本没有足够远,不能成为问题的原因。


2
你确定可以这样使用qtbindings吗?qtbindings是线程安全的吗?你知道Rufus会创建一个新的Ruby线程吗?我认为一旦进入Qt世界,你需要使用Qt定时器而不是Ruby定时器。也就是说,要触发emit,你可能需要使用类似于QTimer而不是Rufus的东西。 - Casper
@Casper,我不知道,我不知道Rufus是否会创建一个新的Ruby线程。即使它不是线程安全的(任何时候仍只有一个线程可以访问它,并且引用似乎也没问题,因为我可以打印一些关于它的信息),这仍然似乎是一种非常奇怪的失败方式。我仍在努力学习QT,并没有意识到我可以使用QTimer,谢谢你提醒我。 - Vala
@Casper,看起来问题并不在那里,导致失败的代码根本没有被Rufus调度程序运行(因为它在初始化期间失败,这应该仍然是主线程)。如果有帮助的话,我已经在问题中添加了更多细节。 - Vala
我不知道这是否相关,但似乎我的小部件的initialize方法被执行了两次。我不知道是什么原因导致了这种情况,也不知道为什么会这样。我肯定在自己的代码中找不到任何参考。 - Vala
2个回答

1

我看到你没有尝试使用更新版本的 Ruby。p0 版本可能存在很多问题。

Ruby 1.9.3-p392 是最新的 1.9.3 版本。


我使用Mint软件包管理器安装了Ruby,它已经不断更新,目前版本是1.9.3p194。虽然不是最新版本,但在我使用它的时间里,我至少尝试过几个不同的补丁版本。这是一个好建议,我会看看是否有时间手动安装最新版本。 - Vala

0

我花了太长时间来解决这个问题,但是无法找出原因(感谢那些尝试帮助我的人,但不幸的是没有解决问题)。因此,我在这里将我的解决方法作为答案发布,以防其他人遇到类似的问题:

我放弃了数组,而是将要使用它的代码包装在一个Proc中,该Proc是我在先前填充数组的循环内创建的。由于在此循环内创建的Proc可以直接访问相关变量,因此不再需要将其存储在数组中并稍后检索。这引起了一两个问题,因为现在Proc中的代码会针对每个SIGNAL执行一次操作,而不是一个代码块通过所有相关操作,但它们显然更容易处理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接