@QCoder

Как последовательно показать результаты изменения одной переменной многими потоками?

Здравствуйте. Я работаю над приложением, которое должно выводить случайную игру на определенную платформу. Для того, чтобы приложение казалось не совсем "сухим" и скучным я решил добавить эффект перелистывания игр, чтобы пользователь мельком увидел еще пару десятков игр на эту платформу. Хотя о многопоточности знаю только по теории и наслышке, сразу подумал о ней, но так как класс модели (класс Model) у меня синхнонный, а асинхронность нужна только для одного метода решил создать еще один класс, который и унаследовал от QThread (класс AsyncRoller). Он принимает указатель на модель и имя платформы в конструкторе и просто вызывает метод из модели, переданной в конструктор. Соответственно, десяток-другой таких потоков я создаю в представлении (нутром чую, что это говнорешение). Ну, так как в многопоточности не сильно смыслю, налепил мьютекс на метод ролла, чтобы потоки не лезли вне очереди. В результате выходит быстрое перелистывание пары игр (1-2). Как синхнонизировать это?

//model.h
class Model: public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString rggGame READ game WRITE setGame NOTIFY gameSet)

private:
    QString currentGame;

public:

    Model(QStringList _platform, QObject* _parent = nullptr);

    QString game();

public slots:
   
    Q_INVOKABLE void rollGame(QString _platform);

    Q_INVOKABLE void asyncRollGame(QString _platform);

    Q_INVOKABLE void setGame(QString _game);

signals:

    void gameRolled(QString _game);

    void gameSet(QString _game);
};


//model.cpp
//...
void Model::rollGame(QString _platform)
{
    static QMutex mute;
    mute.lock();
    QVector<QString> gms;
    QFile games(platformAssignment.value(_platform));
    if(!games.open(QIODevice::ReadOnly))
        qDebug() << "Error opening platform file!";
    while(!games.atEnd())
        gms.append(QString::fromStdString(games.readLine().toStdString()));
    srand(time(0));

    QString gameName = gms[rand() % gms.size()];
    emit gameRolled(gameName);
    setGame(gameName);

    mute.unlock();
}

void Model::asyncRollGame(QString _platform)
{
    AsyncRoller* roller = new AsyncRoller(this, _platform);
    roller->start();
}

void Model::setGame(QString _game)
{
    this->currentGame = _game;
    emit gameSet(this->currentGame);
}


//AsyncRoller.h
class AsyncRoller : public QThread
{
private:
    Model* model;
    QString platform;
public:
    AsyncRoller();
    AsyncRoller(Model* _mdl, QString _platform);
    void run();
};


//AsyncRoller.cpp
AsyncRoller::AsyncRoller(Model* _mdl, QString _platform)
{
    model = _mdl;
    platform = _platform;
}

void AsyncRoller::run()
{
    model->rollGame(platform);
}
  • Вопрос задан
  • 262 просмотра
Решения вопроса 1
@vilgeforce
Раздолбай и программист
А зачем вам потоки, тем более в количестве нескольких десятков?
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Nipheris
@Nipheris Куратор тега C++
> Просто синхронные вызовы ролла показывают лишь последний результат.
ну так а почему асинхронность сразу значит - несколько потоков? И причем тут вообще асинхронность - вам нужно сделать нормальную анимацию, анимация - это отрисовка кадров в соответствии с ходом времени. Последний результат виден потому, что вы не возвращаете управление в цикл приложения, чтобы оно могло нормально обработать прочие сообщения. Уберите всю эту многопоточность, сгенерьте рандомом перед анимацией все игры, которые хотите мельком показать, поставьте обыкновенный таймер (QTimer) и отрисовывайте по сигналу таймера игры по очереди, пока не дойдете до последней - той что "выпала". Разберитесь с матчастью по mainloop и анимации и все станет ясно как божий день. Еще раз - никаких потоков для вашей задачи вам не надо, тем более 20 штук.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы