Почему я получаю ошибку сегментации (qtruby)?

У меня была проблема с ошибками сегментации при доступе к переменной класса (массив Qt::Actions), и я пытался свести его к минимальному примеру кода, который повторяет проблему:

#!/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 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,

.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, который обращается к actions массив. На этом этапе все это должно быть в одном потоке, ни одна из этих строк не зависит от QT, кроме фактического создания Qt::Action, Я удалил расписание Rufus и заменил его QTimer, но это просто недостаточно далеко, чтобы это стало проблемой.

2 ответа

Решение

Я потратил слишком много времени на это, не имея возможности понять, почему это происходит (спасибо тем, кто пытался помочь, но, к сожалению, это не решило проблему). Таким образом, я размещаю здесь свое решение в качестве ответа на случай, если у кого-то еще есть подобная проблема:

Я покончил с массивом, вместо этого оборачивая код, который должен был использовать его в Proc что я создаю внутри цикла, который ранее заполнял массив. Так как Proc созданный в этом цикле имеет прямой доступ к рассматриваемой переменной, больше нет необходимости сохранять его в массиве и извлекать его позже. Он поднял один или два собственных вопроса, так как код в Proc теперь выполняется один раз за действие в SIGNAL вместо того, чтобы один блок кода выполнял все соответствующие действия, но с ними было значительно легче справиться.

Одна вещь, которую я не вижу, вы пытались использовать более новую версию ruby. p0, кажется, потенциально изобилует проблемами.

Ruby 1.9.3-p392 является последней версией 1.9.3.

Другие вопросы по тегам