2013-05-18 4 views
1

В принципе у меня есть программа, которая запускает новый поток, а затем пытается сделать материал в этом новом потоке. Тем не менее, новый поток, кажется, застревает до тех пор, пока основной поток не достигнет конца программы.thread get stuck (python)

вот рабочий пример проблемы, которую я испытываю. кажется, что для этой проблемы должно существовать gtk.main(). если я использую что-то вроде input(), проблема не возникает.

import threading,sys 
class MyThread(threading.Thread): 
    def run(self): 
     import time 
     print('before') 
     time.sleep(3) 
     print('after') 

MyThread().start() 

from gi.repository import Gtk as gtk 

class My_window: 
    def __init__(self): 
     self.window = gtk.Window() 
     self.window.connect("delete_event", gtk.main_quit) 
     self.button = gtk.Button("Hello World") 
     self.window.add(self.button) 
     self.button.show() 
     self.window.show() 

My_window() 
gtk.main() 

Что должно случится: Появится окно, до появления слова, и через 3 секунды слово после появления

Что на самом деле происходит: появляется окно, слово, прежде чем появляется, то ничего не происходит. Когда вы закрываете окно, появляется слово after. (Как будто как-то подходит к концу программы делает все запущенные потоки, которые были заморожены до того, бег снова)

Вещи, которые я пробовал:

  • Заменено time.sleep с другими функциями, подобно команда терминала или цикл занятости. Я получаю те же результаты

  • Я попытался воссоздать проблему без окна и других дополнительных материалов, но не смог. поэтому я не знаю, где находится эта проблема, поэтому я дал всю информацию о предыстории, которая могла бы.

  • Я попытался использовать sys.stdout.flush(), чтобы убедиться, что текст действительно отображается в командной строке, когда это необходимо. Это было.

Есть ли у кого-нибудь какие-либо предложения относительно проблемы?

Я использую Python 3 (и GTK для окна), и предпочел бы мою программу, чтобы быть совместимым на всех основных ОС

редактирования:

Я попытался положить Принг ('отправную ') перед gtk.main(). результат показывался до начала, а затем после. Я думаю, что вызов gtk.main замораживает все потоки, а когда gtk.main заканчивается, то потоки возобновляются.

редактировать 2: никогда не ум, в моей orriginal программы, поток был создан в то время как gtk.main работает, но все еще может быть что-то в gtk.main, что замерзает нить, что называют время от времени.

+0

Вы проверили, что 'sys.stdout' является реальным процессом stdout, а не какой-то странной оболочкой, добавленной GTK? Работает ли он, если вы пишете '' before'' и '' after'' в файл вместо того, чтобы печатать на stdout? – Aya

+0

это не похоже на это. до и после импорта gtk я набрал sys.stdout, он показал тот же адрес памяти оба раза. – QxQ

+0

@aya, при записи в файл ничего не отображается в файле до тех пор, пока окно не завершится. кажется, что если команда требует много времени для выполнения, тогда команда застревает. так как для выполнения f.write ('before') требуется больше времени, а затем print ('before'), я думаю, что он застревает на f.write ('before') вместо time.sleep (3), поэтому печать не выполняется Кажется, проблема – QxQ

ответ

2

мне удалось воспроизвести это, и потратил возрастов, пытаясь понять, почему он терпел неудачу, пока я не наткнулся на this FAQ entry, который предложил положить ...

import gobject 
gobject.threads_init() 

... в верхней части кода , что, как представляется, устраняет проблему.

Мое предположение заключается в том, что после вызова gtk.main() GTK держится на Global Interpreter Lock Python, что немного непослушно для поведения по умолчанию, но по крайней мере есть способ предотвратить его.

Обратите внимание, что фоновые потоки не могут напрямую манипулировать объектами GTK, поэтому вам нужно будет передать сообщения в основной поток, чтобы сделать это вместо этого.

+0

работает! Спасибо за помощь. он выглядит как импортировать его для python 3, вы должны использовать 'from gi.repository import GObject' – QxQ

+0

@QxQ Упс. Я забыл об этом. Я тестировал Python 2.7.3, поэтому мне пришлось заменить ваш 'from gi.repository импорт Gtk как gtk' на' import gtk' и забыл перевести обратно. – Aya

0

Если th - объект потока, который вы создали, перед тем, как запустить его, вы должны выполнить th.setDaemon (1), иначе основной поток не выйдет без потока, с которого вы сначала вышли.

+0

это не исправить проблему. – QxQ

+0

Я думаю, что time.sleep каким-то образом вмешивается в основной цикл gtk, закомментируйте, что он напечатает ваши «до» и «после» – frostyplanet

+0

, но это победит цель. в моей первоначальной программе я фактически запускал там команду терминала, которая не выходила на некоторое время, но когда она завершалась, я столкнулся с этой проблемой, где остальная часть кода не запускалась. Я представляю эту команду терминала с помощью time.sleep. – QxQ