LINUX.ORG.RU

pygtk and threadы

 ,


1

1

есть TreeView на раскрытие узла в отдельном треде пытаюсь добавить дочерние

class UpdateTV(threading.Thread):
    def __init__(self, tv, iter):
        super(UpdateTV, self).__init__()
        self.tv = tv
        self.iter = iter
        self.status_run = False

    def run(self):
        #
        self.status_run = True

        model = self.tv.get_model()
        for i in range(10):
            if not self.status_run:
                break

            model.append(self.iter, ["Added_node#", str(i)])

высыпается в Gtk-CRITICAL **: gtk_tree_store_insert_with_valuesv: assertion `VALID_ITER (parent, tree_store)' failed

весь example http://bpaste.net/show/162777/

★★★★
Ответ на: комментарий от tailgunner

если не сложно на текущем примере подскажи

deity ★★★★
() автор топика

Тут не получится просто подсказать, потому что ИМХО так, как делаешь ты, делать нельзя совсем - ты создаешь нить, которая сразу же лезет менять модель, вообще без всякой синхронизации. Просто исходя из здравого смысла, доступ к общим данным должен лочиться. Вдобавок, ЕМНИП, PyGtk внутри себя не threadsafe, поэтому нужны трюки вроде http://faq.pygtk.org/index.py?file=faq20.006.htp&req=show

Если коротко, попробуй заключить тело UpdateTV.run в gtk.threads_enter()/gtk.threads_leave()

Ах да, и еще: возможно, в новых Python и PyGtk приняты какие-то други способы синхронизации :)

tailgunner ★★★★★
()
Ответ на: комментарий от anonymous

Run залочит гуй наскооько я понимаю

UpdateTV.run? Я не вижу, чтобы он что-то лочил, поэтому предложил gtk.threads_enter()/gtk.threads_leave().

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Вроде лочилось на больших запрсах. Как доберусь до компа попробую, срасибо.

anonymous
()
Ответ на: комментарий от deity

цикл зависает на первой итерации.

Это относится к опубликованному варианту кода или коду с моим исправлением?

В любом случае, хотя я и не уверен, что проблема связана с нитями, попробуй сделать так, как описано по ссылке, т.е. после завершения работы нити добавь коллбек, который выполнит вставку в дерево. Как-то так:

import gobject

...

class UpdateTV:

  def run(self):
    # делается работа
    # ...
    # добавляется коллбек метода окна (объект-окно придется пробросить в UpdateTV)
    gobject.idle_add(self.wnd.added_node, nodedata)
    return

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

проблема с нитями, тот же код в теле выполняется. По приведенному примеру у меня ступор, посижу еще подумаю

deity ★★★★
() автор топика
Ответ на: комментарий от deity

По приведенному примеру у меня ступор, посижу еще подумаю

Просто добавь в TestWnd метод

def added_node(self, node_data): print(node_data)
tailgunner ★★★★★
()
Ответ на: комментарий от deity

Тебе не надо трогать gtk из воркер треда, а надо общаться с главным через очередь сообщений. Товарищ тебе предлагает повесить отложенное событие в майнлуп, который крутится только в главном треде, и, соответсвенно, колбэк выстрелит именно в нем. То есть использовать майнлуп в качестве очереди. Мысль единственно здравая из всех возможных здесь.

arturpub ★★
()
Ответ на: комментарий от tailgunner

новых […] PyGtk

Хорошая шутка. Его ещё в 2011 закопали и предложили переползать на pygobject со всей этой Gtk3-интроспекцией.

x3al ★★★★★
()
Ответ на: комментарий от x3al

новых […] PyGtk

Хорошая шутка.

Ты просто не очень хорошо знаешь русский.

Его ещё в 2011 закопали

Тем не менее он вполне работает.

tailgunner ★★★★★
()
Ответ на: комментарий от arturpub

так тоже не совсем выходит.

(testtree.py:2458): Gtk-CRITICAL **: gtk_tree_store_insert_with_valuesv: assertion `VALID_ITER (parent, tree_store)' failed

или вообще не передавать iter передать лист со значениями и уже в майнлупе добавлять...

deity ★★★★
() автор топика
Ответ на: комментарий от deity

даже в основном треде валиться на невалидный TreeIter

Код в студию. Подозреваю, что ты создаешь итератор в другой нити.

tailgunner ★★★★★
()
Ответ на: комментарий от deity

Да, код в студию, и нужно уточнить, что даже модель на чтение нельзя в воркере использовать. Вообще ничего гткшного, кроме нескольких разрешенных функций. Воркер должен быть чистым генератором данных откуда-то там, а вставка и вычисление ее места должно происходить в главном.

arturpub ★★
()

Я тут твой код случайно глянул, а он у тебя без тредов-то работает? Ты там берешь итер, а потом какую-то ноду-заглушку удаляешь, это разве не инвалидирует все полученные итеры?

arturpub ★★
()
Ответ на: комментарий от arturpub

Я тут твой код случайно глянул, а он у тебя без тредов-то работает?

Вот и я об этом спросил %) Но с нитями там больше ругани от Gtk.

tailgunner ★★★★★
()
Ответ на: комментарий от deity

Оке, дело точно не в невалидном итере. Нужно не итер передавать в тред, а что-то, что идентифицирует ноду. Представим что это фс. У тебя там [-1, None], вот вместо None и положи путь к каталогу. Пусть воркер получит имена файлов и запостит их в idle, как выше советовали. В главном треде во вставочной функции строчку найдешь заново по тому же пути.

Надо понимать, что генерация данных может идти секунды-минуты и за это время многие ноды могут добавляться-удаляться-разворачиваться, поэтому однозначно рассчитывать на то, что можно запомнить место, или что вообще будет куда вставлять — нельзя. Поэтому надо сказать воркеру, что конкретно генерить, а потом самому решать к чему относится результат. Итеры здесь само собой в пролете, канают только естественные ключи.

arturpub ★★
()
Ответ на: комментарий от arturpub

Нужно не итер передавать в тред, а что-то, что идентифицирует ноду

я уже тоже об этом думал, можно путь ноды передать и данные в основной

deity ★★★★
() автор топика
Ответ на: комментарий от deity

Похоже, к нитям это не имеет никакого отношения. У тебя просто итератор становится невалидным (сохранять созданный кем-то итератор - это, мягко говоря, сомнительная идея). Попробуй таскать между объектами TreePath или собственноручно созданный итератор.

    def add_node(self, node_data, it):
        model = self.tv_tree.get_model()
        it = model.get_iter(Gtk.TreePath(0))
        self.model.append(it, node_data)

Так работает (по крайней мере, узлы добавляются).

tailgunner ★★★★★
()
Ответ на: комментарий от deity

походу не в нитях было дело

Мне давно так кажется %)

тут в треде добавляет без проблем..

Может, Gtk3 стал threadsafe, а может, ошибки синхронизации, как обычно, проявляются отнюдь не всегда.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

перенес add_node в тело треда c вызовом через GObject.idle_, увеличив итерацию до 1к вылетов не наблюдаю:

 class UpdateTV(threading.Thread):
    def __init__(self, model, path):
        super(UpdateTV, self).__init__()
        self.status_run = False
        self.model = model
        self.path = path

    def add_node(self, node_data):
        _iter = self.model.get_iter_from_string(self.path)
        if self.model.iter_is_valid(_iter):
            self.model.append(_iter, node_data)
        else:
            print("FUCK")

    def run(self):
        self.status_run = True
        for i in range(10000):
            if not self.status_run:
                break
            print(i)
            GObject.idle_add(self.add_node, ["Added_node#", str(i)])

    def halt(self):
        self.status_run = False

deity ★★★★
() автор топика
Ответ на: комментарий от deity

перенес add_node в тело треда c вызовом через GObject.idle_

Зачем? Коллбек, добавляемый через idle_add, вызывается на основной нити («в майнлупе», как ты выражаешься).

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Второе конечно же. Если у вас щас заработает мультитред, это не значит, что оно не повалится прямо на рабочем месте.

arturpub ★★
()
Ответ на: комментарий от deity

перенес add_node в тело треда c вызовом через GObject.idle_

Ты в тело класса перенес, не треда. У тебя просто путаница из-за того, что «объект класса и есть тред», а это не очень так.

arturpub ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.