0

私はかなり単純に聞こえることをやろうとしていますが、あらゆる種類の問題に遭遇し続けています. PyQt を使用して、同時に複数のファイルを追跡できる GUI を作成しようとしています。純粋なPythonでファイルを追跡する方法に関するこの回答を見ました

Pythonでログファイルを追跡するにはどうすればよいですか?

QThread 内でこのコードを使用してみました。ここで私が抱えている問題は、テール プロセスが自動的に停止しないことです。殺す必要があります。GUI を閉じたときに強制終了する必要があります。以下のこの特定のソリューションで発生している他の問題は

QThread: Destroyed while thread is still running

QWaitCondition::wakeAll(): mutex lock failure: 

QThread: Destroyed while thread is still running
Traceback (most recent call last):
  File "./tailer.py", line 27, in run
    self.emit(SIGNAL('newline'), line.rstrip())
RuntimeError: underlying C/C++ object has been deleted

私が試した他の実装では、末尾のプロセスがパイプの破損について不平を言っていましたが、 stderr=PIPE を実行すると、それらは表示されなくなりました。stderr から読み取ったことがないため、エラーが発生する可能性があるのではないかと心配しています (ブロックされ、出力がないはずなので)。

エラーを取得するには、これを起動して、3 つの異なるファイルを追跡しようとします。0.1 秒のスリープを実行して、ループして 3 つのファイルに書き込む別のスクリプトを作成しました。GUI を閉じて、何度も起動します。エラーが発生する場合とそうでない場合があります。

私がここで間違っていることを教えてください。

#!/usr/bin/env python

from PyQt4.QtCore import *
from PyQt4.QtGui import *

import os
from subprocess import Popen, PIPE

class Tailer(QThread):

    def __init__(self, fname, parent=None):
        super(Tailer, self).__init__(parent)
        self.fname = fname
        self.connect(self, SIGNAL('finished()'), self.cleanup)

    def cleanup(self):
        print 'CLEANING UP'
        self.p.kill()
        print 'killed'

    def run(self):
        command = ["tail", "-f", self.fname]
        print command
        self.p = Popen(command, stdout=PIPE, stderr=PIPE)
        while True:
            line = self.p.stdout.readline()
            self.emit(SIGNAL('newline'), line.rstrip())
            if not line:
                print 'BREAKING'
                break

    def foo(self):
        self.p.kill()

class TailWidget(QWidget):
    def __init__(self, fnames, parent=None):
        super(TailWidget, self).__init__(parent)
        layout = QGridLayout()
        self.threads = {}
        self.browsers = {}
        for i, fname in enumerate(fnames):
            if not os.path.exists(fname):
                print fname, "doesn't exist; creating"
                p = Popen(['touch', fname], stdout=PIPE, stderr=PIPE)
                out, err = p.communicate()
                ret = p.wait()
                assert ret == 0
            t = Tailer(fname, self)
            self.threads[fname] = t
            b = QTextBrowser()
            self.browsers[fname] = b
            layout.addWidget(QLabel('Tail on %s' % fname), 0, i)
            layout.addWidget(b, 1, i)
            self.connect(t, SIGNAL("newline"), b.append)
            t.start()
        self.setLayout(layout)

    def closeEvent(self, event):
        for fname, t in self.threads.items():
            t.foo()

if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    tw = TailWidget(sys.argv[1:])
    tw.show()
    sys.exit(app.exec_())
4

1 に答える 1

0

問題は、メイン スレッドがバックグラウンド スレッドで待機していないことです。

あなたは彼らにここでやめるように言います:

def closeEvent(self, event):
    for fname, t in self.threads.items():
        t.foo()

したがって、これによりすべてのサブプロセスが強制終了され、最終的にすべてのバックグラウンド スレッドが終了します。しかし、すぐにやめさせるわけではありません。それは、次にそれぞれが に到達するまで起こりませんreadline

サブプロセスを強制終了した後、戻り、Qt がすぐにウィンドウを閉じてウィジェットを破棄できるようにします。そのウィジェットにシグナルを送信しようとするバックグラウンド スレッドは失敗します。

スレッド 1 が を実行しreadline、その途中でrstripスレッド 0 が終了しようとしているとします。したがって、スレッド 0 はスレッド 1 のサブプロセスを強制終了し、メイン ウィジェットを削除します。スレッド 1 はrstripと の呼び出しemitを終了し、現在は削除されたウィジェットに送信しています。

于 2013-06-24T20:18:30.960 に答える