Внедрить многопоточную среду - PullRequest
1 голос
/ 26 мая 2010

Я хочу реализовать многопоточную среду с использованием Qt4. Идея заключается в следующем в C ++ - как псевдокод:

class Thread : public QThread {
    QList<SubThread*> threads_;

public:
    void run() {
        foreach(SubThread* thread : threads) {
            thread.start();
        }

        foreach(SubThread* thread : threads) {
            thread.wait();
        }
    }

    void abort() {
        foreach(SubThread* thread : threads) {
            thread.cancel();
        }
    }

public slots:
    // This method is called from the main-thread
    // (sometimes via some signal-slot-connection)
    void changeSomeSettings() {
        abort();
        // change settings
        start();
    }
}

class SubThread : public QThread {
    bool isCancelled_;

public:
    void run() {
        while(!isCancelled or task completed) {
            // something that takes some time...
        }
    }

    void cancel() {
        if(isRunning() {
            isCancelled_ = true;
        }
    }
}

Цель состоит в том, чтобы слот changeSomeSettings () убивал все запущенные потоки, фиксировал его изменения и перезапускал. Чего я хочу добиться, так это того, что после запуска этого метода он вызывает «abort», а затем ждет завершения всех потоков. Неправильное использование мьютексов:

    void Thread::changeSomeSettings() {
        mutex1.lock();
        abort();

        mutex2.lock();

        start();
        mutex1.unlock();
    }

    void Thread::run() {
        foreach(Thread* thread : threads) {
            thread.start();
        }

        foreach(Thread* thread : threads) {
            thread.wait();
        }

        mutex2.unlock();
    }

На самом деле это работает в Qt под MacOSX, но согласно документации mutex2 должен быть разблокирован в том же потоке (и в Windows я получаю сообщение об ошибке). Как лучше всего достичь своей цели, не сталкиваясь с гоночными условиями и тупиками? Есть ли лучший дизайн, чем тот, который я предложил здесь?

1 Ответ

2 голосов
/ 26 мая 2010

Возможно, вы захотите использовать условную переменную вместо мьютекса в этой ситуации. Условная переменная - это способ для одного потока сигнализировать другому. Реализация QT выглядит как QTWaitCondition :

Возможно, дочерний поток периодически проверяет состояние условной переменной. Это можно сделать с помощью QTWaitCondition :: wait () с коротким тайм-аутом / 0. Если это сигнализируется, тогда заблокируйте область общей памяти, содержащую обновленные данные, и получите доступ к данным, которые должны быть обновлены. Тогда этот поток может безопасно перезапустить себя соответственно.

Обычно не стоит просто прерывать поток. Вы можете потерять память / ресурсы / ручки / блокировки / и т. Д. Вы не знаете, где находится этот поток в его стеке вызовов, и не может быть никаких гарантий, что этот стек будет «размотан» для вас и будут вызваны все деструкторы. Это еще одна причина, по которой дочерние потоки периодически проверяют переменную условия на наличие обновленных данных и заставляют их безопасно перезапускаться с новыми данными.

...