Как мне обрабатывать сигналы в основном потоке с заблокированным мьютексом? - PullRequest
0 голосов
/ 05 апреля 2019

Я пишу многопоточное приложение Qt, но из-за вызовов, связанных с OpenGL, некоторая часть кода должна всегда выполняться в главном потоке.

Примерный код для симуляции проблемы будет:

QMutex mutex;

void openGLCalls()
{
}
void foo1()
{
    mutex.lock();
    openGLCalls();
    mutex.unlock();

}

class CBHandler : public QObject
{

public:
    CBHandler(QObject *parent = NULL)
    {
        connect(this, SIGNAL(requestCallbackExec()), SLOT(runCallback()),    Qt::BlockingQueuedConnection);

    }

    static CBHandler *Instance();

    public slots:

    void runCallback  ()
    {
        //in the main thread as object lies there
        openGLCalls();
    }

signals:
    void requestCallbackExec ();

};

class Thread1
{
    void run()
    {
        while(1)
        {
            mutex.lock();
            CBHandler::Instance()->emit requestCallbackExec();
            mutex.unlock();
        }
    }
};

void main()
{

    Thread1 thread;
    CBHandler cbhandler;
    thread.start();
    while(1)
    {
        if(/*some key pressed*/)
        {
            foo1();
        }
    }
}

Приведенный выше код гарантирует, что openGLCalls () всегда выполняется в основном потоке.Но проблема в том, что если мьютекс заблокирован потоком 1 и основной поток пытается вызвать foo1, то основной поток спит при попытке заблокировать мьютекс.А поскольку основной поток находится в спящем режиме, мьютекс, заблокированный Thread1, никогда не разблокируется из-за того, что сигнал 'requestCallbackExec' никогда не обрабатывается.

1 Ответ

0 голосов
/ 06 апреля 2019

Вы должны позволить циклу событий вращаться, пока .lock() ожидает. Кажется, нет никакого способа сделать это. Так что вы могли бы подождать:

while(!mutex.tryLock()) {
    QEventLoop loop;
    loop.processEvents();
}

Вы можете добавить тайм-аут к вызову .tryLock(), чтобы не нагревать процессор, но это будет стоить вам некоторой задержки.

...