2

私の Qt アプリケーションには、Qt gui (基本的にいくつかのボタンと、データを描画する opengl コンテキスト) があります。また、PythonQt クラスを利用したスクリプト可能性も追加しました。コマンドは PythonQtScriptingConsole 内から評価されます。

コンソールを介して現在の python コンテキストを介して C++ 呼び出しを送信するラッパー クラスとファクトリ メソッドを明示的に作成しましたが、コンソール内から長いタスクを実行すると、イベント ループが処理されないため、GUI がフリーズします。したがって、最初の解決策はタイマーでイベントループを処理することですが、これは遅くてちょっとばかげていると思うので、好きではありません。あ

誰かが何かヒントを持っていますか?Python Global Interpreter Lock はここで問題になりますか?

4

1 に答える 1

5

はい、Python への長い呼び出しが UI スレッドを介して実行されているため、GUI がフリーズしています。これを回避するために、QThread をサブクラス化し、Command パターンを介して Python モジュールにコマンドを発行することができました。

次のクラスを使用して複数の Python モジュールの呼び出しを開始する前に、main() 関数で確認できるように、PyEval_InitThreads() を呼び出して Python のスレッド サポートを初期化してください。

幸運を!

int main( int argc, char **argv ) {

        QApplication qapp(argc, argv);

        PyEval_InitThreads(); // IMPORTANT
        PythonQt::init(PythonQt::IgnoreSiteModule | PythonQt::RedirectStdOut);

        PythonQtObjectPtr module = PythonQt::self()->createUniqueModule();

        ThreadedPythonContext context(module);
        context.start();

        # issue some commands into the module
        context.issue("import sys");
        context.issue("sys.path.append('C:\\Python27\\Lib\\site-packages')");
        context.issue("import time");
        context.issue("last = time.localtime().tm_sec");

        // Release the global interpreter lock (if it has been created and thread support 
        // is enabled) and reset the thread state to NULL, returning the previous thread 
        // state (which is not NULL). If the lock has been created, the current thread must 
        // have acquired it. (This function is available even when thread support is 
        // disabled at compile time.)

        // give up control of the GIL
        PyThreadState *state = PyEval_SaveThread();

        return qapp.exec()
}

ThreadedPythonContext.h

#ifndef THREADEDPYTHONCONTEXT_H
#define THREADEDPYTHONCONTEXT_H

#include "PythonQt.h"

#include <QtCore/QMutexLocker>
#include <QtCore/QQueue>
#include <QtCore/QThread>
#include <QtCore/QWaitCondition>

class ThreadedPythonContext : public QThread 
{
    Q_OBJECT
public:
    ThreadedPythonContext(const PythonQtObjectPtr &context) : 
        QThread(), 
        _context(context), 
        _running(true)
    {
    }

    ~ThreadedPythonContext() {
        _running = false;
        wait();
    }
    void issue(const QString &code) {
        _lock.lock();
        _commands.enqueue(code);
        _lock.unlock();

        _CommandQueued.wakeOne();
    }

    bool isCommandQueueEmpty() {
        QMutexLocker lock(&_lock);
        return _commands.isEmpty();
    }

protected:

    QString dequeue() {
        QMutexLocker lock(&_lock);
        QString cmd( _commands.dequeue() );

        return cmd.isEmpty() ? "\n" : cmd;
    }

    void run() {

        QMutex signal;
        PyGILState_STATE state;

        while(_running) {

            // wait to be signaled ... 
            signal.lock();
            _CommandQueued.wait(&signal,1);
            signal.unlock();

            if ( isCommandQueueEmpty() ) {
                continue;
            }

            while ( !isCommandQueueEmpty() ) {

                PythonQtObjectPtr p;
                PyObject* dict = NULL;

                state = PyGILState_Ensure();

                if (PyModule_Check(_context)) {
                    dict = PyModule_GetDict(_context);
                } else if (PyDict_Check(_context)) {
                    dict = _context;
                }

                if (dict) {
                    // this command blocks until the code has completed execution
                    emit python_busy(true);
                    p.setNewRef(PyRun_String(dequeue().toLatin1().data(), Py_single_input, dict, dict));
                    emit python_busy(false);
                }

                // error in the kernel
                if (!p) {
                    PythonQt::self()->handleError();
                }   
                PyGILState_Release(state);
            }
        }
    }

    PythonQtObjectPtr _context;

    QMutex _lock;
    QQueue<QString> _commands;

    QWaitCondition _CommandQueued;  
    bool _running;

signals:
    void python_busy(bool);
};

#endif //THREADEDPYTHONCONTEXT_H
于 2013-08-05T16:38:41.000 に答える