Russian Qt Forum

Qt => Вопросы новичков => Тема начата: SydoQQ от Апрель 26, 2017, 12:02



Название: Стандартные потоки C++ в Qt
Отправлено: SydoQQ от Апрель 26, 2017, 12:02
Доброго времени суток!
Столкнулся с одной проблемой, при использовании стандартных потоков в Qt, использую версию 5.7. Нашел строку, из-за которой происходит крах программы, это строка 49. При комментировании ее, естественно программа работает на ура. И самый интересный момент, если в функию
Код:
LineItem->setPos(0,returnLinePosition());
всегда передавать константу, например вот так
Код:
LineItem->setPos(0,0);
, или
Код:
 int n=100; LineItem->setPos(0,n);
, то программа тоже работает на ура. Испробовал много чего, но не могу понять, почему так происходит, надаеюсь кто то поможет мне решить данную проблему. Пробывал использовать таймер, но результат получается не такой, как хотелась бы.
Вот полный код .cpp
Код:
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //setWindowFlags(Qt::FramelessWindowHint);

    Scene=new QGraphicsScene(this);
    View=new QGraphicsView(Scene);
    setGeometry(300,100,400,600);
    View->setParent(this);
    setMaximumSize(width(),height());
    View->setFixedSize(width(),height());
    View->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    View->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    LineItem=Scene->addRect(QRect(-(width()/2)+1,0,width()-2,0),QPen(Qt::blue,2));

    H=height();
    LinePosition=600;
    backGroundGradient=new QLinearGradient(QPoint(0,H),QPoint(0,0));
    for(int i=0;i<3;i++)
    {
        FC[i]=0;
        SC[i]=0;
        LC[i]=0;
    }
    std::thread BackGroundTH{&MainWindow::on_BACKgroundChange,this};
    BackGroundTH.detach();

    std::thread MoveLineTH{&MainWindow::Line_Move,this};
    MoveLineTH.detach();

//    timer=new QTimer(this);
//    connect(timer,SIGNAL(timeout()),this,SLOT(Line_Move()));
//    timer->start(100);

}

MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::newPosition_line()
{   
    linePositionMutex.lock();
    LineItem->setPos(0,returnLinePosition());
    linePositionMutex.unlock();

}
void MainWindow::Line_Move()
{
    //timer->stop();
    int newPosition=0;
    int C=1;
    linePositionMutex.lock();
    int n=1+qrand()%100;
    for(int i=0;i<n;i++)
    {
        newPosition+=qrand()%(H*2);
    }
    linePositionMutex.unlock();
    newPosition/=n;
    if(LinePosition<newPosition)
        C=1;
    else
        C=-1;
    for(int i=0;i<fabs(LinePosition-newPosition);i++)
    {
        LinePosition+=C*1;
        linePositionMutex.lock();
        QThread::msleep(10);
        linePositionMutex.unlock();
        newPosition_line();
    }
    //timer->start(100);
    Line_Move();
}

int MainWindow::returnLinePosition()
{
    return LinePosition-(H-1);
}

void MainWindow::on_backgroundColor_change()
{
    backGroundMutex.lock();
    Scene->setBackgroundBrush(returnGradient());
    backGroundMutex.unlock();
}

void MainWindow::on_BACKgroundChange()
{
    int masF[3]={0,0,0};
    int masS[3]={0,0,0};
    int C=1;
        srand(QTime::currentTime().toString("s").toInt());
        backGroundMutex.lock();
        for(int i=0;i<3;i++)
        {
            masF[i]=rand()%255;
            masS[i]=rand()%255;
        }
        backGroundMutex.unlock();
        for(int i=0;i<3;i++)
        {
            if(FC[i]<masF[i])
                C=1;
            else
                C=-1;
            for(int j=0;j<fabs(FC[i]-masF[i]);j++)
            {
                backGroundMutex.lock();
                QThread::usleep(100000);
                backGroundMutex.unlock();
                FC[i]+=C*1;
                backGroundGradient->setColorAt(0,QColor(SC[0],SC[1],SC[2]));
                backGroundGradient->setColorAt(0.9,QColor(FC[0],FC[1],FC[2]));
                on_backgroundColor_change();
            }
        }
        for(int i=0;i<3;i++)
        {
            if(SC[i]<masS[i])
                C=1;
            else
                C=-1;
            for(int j=0;j<fabs(SC[i]-masS[i]);j++)
            {
                backGroundMutex.lock();
                QThread::usleep(100000);
                backGroundMutex.unlock();
                SC[i]+=C*1;
                backGroundGradient->setColorAt(0,QColor(SC[0],SC[1],SC[2]));
                backGroundGradient->setColorAt(0.9,QColor(FC[0],FC[1],FC[2]));
                on_backgroundColor_change();
            }
        }
        on_BACKgroundChange();
}

QGradient MainWindow::returnGradient()
{
    return *backGroundGradient;
}

.h файла
Код:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsItem>
#include <thread>
#include <mutex>
#include <QThread>
#include <QTime>
#include <QTimer>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    void newPosition_line();
    void Line_Move();
    int returnLinePosition();
    void on_backgroundColor_change();
    void on_BACKgroundChange();
    QGradient returnGradient();
public slots:
    //void Line_Move();
signals:

private:
    Ui::MainWindow *ui;
    QGraphicsScene *Scene;
    QGraphicsView *View;
    QGraphicsItem *LineItem;
    int LinePosition;
    int H;
    int FC[3];
    int SC[3];
    int LC[3];
    QGradient *backGroundGradient;
    std::mutex backGroundMutex;
    std::mutex linePositionMutex;
    //QTimer *timer;

};

#endif // MAINWINDOW_H
Сообщения которое пишет отладчик
Код:
QObject::startTimer: Timers cannot be started from another thread
И я вижу что проблема с таймером, но я не понимаю откуда она возникает.


Название: Re: Стандартные потоки C++ в Qt
Отправлено: Пантер от Апрель 26, 2017, 12:13
Ты неправильно работаешь с потоками.
1. Используй QThread
2. С GUI можно работать напрямую только из основного потока, другие потоки должны использовать сигнал/слоты.


Название: Re: Стандартные потоки C++ в Qt
Отправлено: SydoQQ от Апрель 26, 2017, 15:28
Ты неправильно работаешь с потоками.
1. Используй QThread
2. С GUI можно работать напрямую только из основного потока, другие потоки должны использовать сигнал/слоты.
Тогда возникает вопрос, почему QGraphicsScene работает нормально, хотя тоже изменяется в потоке. И я пробывал использовать QThread, однако у меня происходило зацикливание и крах программ, может я не правильно его использовал, но я прочитал достаточно статей, и на хабре и у шлея. Не могли бы вы скинуть рабочий пример?!


Название: Re: Стандартные потоки C++ в Qt
Отправлено: gil9red от Апрель 26, 2017, 22:20
QGraphicsScene это модель с данными, сама она не рисует в GUI, этим QGraphicsView занимается


Название: Re: Стандартные потоки C++ в Qt
Отправлено: SydoQQ от Апрель 27, 2017, 06:45
QGraphicsScene это модель с данными, сама она не рисует в GUI, этим QGraphicsView занимается
Тогда не могли бы вы подсказать, в каком мне направлении копать, что бы все работало нормально?!


Название: Re: Стандартные потоки C++ в Qt
Отправлено: gil9red от Апрель 27, 2017, 09:08
Я просто ответил на вопрос :)
Цитировать
Тогда возникает вопрос, почему QGraphicsScene работает нормально, хотя тоже изменяется в потоке.


Название: Re: Стандартные потоки C++ в Qt
Отправлено: Igors от Апрель 27, 2017, 09:44
Тогда возникает вопрос, почему QGraphicsScene работает нормально, хотя тоже изменяется в потоке.
Как говорят
Цитировать
Тестирование может показать наличие багов, но не их отсутствие.
Т.е. если какая-то ветка у Вас работает - это совсем не значит что проблем нет

Если исходники больше странички текста или их хотя бы 2, то прочитать/осмыслить их на форуме трудно, проще игнорировать этот топик. Выкладывайте в виде zip архива с компилируемым примером внутри

Чего искать приключений со "стандартными потоками"? С QThread возможно ответят 10 человек т.к. знают и работают с этим, а с std::thread - ну может один. И что там хорошего в std::thread?
Код:
std::thread BackGroundTH{&MainWindow::on_BACKgroundChange,this};
BackGroundTH.detach();

std::thread MoveLineTH{&MainWindow::Line_Move,this};
MoveLineTH.detach();
Так Вы запустили нитки для одноразовой работы - и теперь должны сами возюкаться как организовать их ожидание. Зачем если QThread это делает по дефаулту ?

И в любом случае святая правда что хватать UI из НЕ главной нитки - НИЗЗЯ!

Тогда не могли бы вы подсказать, в каком мне направлении копать, что бы все работало нормально?!
Перейти на QThread и задействовать слот/сигнал


Название: Re: Стандартные потоки C++ в Qt
Отправлено: SydoQQ от Апрель 27, 2017, 16:40
Тогда возникает вопрос, почему QGraphicsScene работает нормально, хотя тоже изменяется в потоке.
Как говорят
Цитировать
Тестирование может показать наличие багов, но не их отсутствие.
Т.е. если какая-то ветка у Вас работает - это совсем не значит что проблем нет

Если исходники больше странички текста или их хотя бы 2, то прочитать/осмыслить их на форуме трудно, проще игнорировать этот топик. Выкладывайте в виде zip архива с компилируемым примером внутри

Чего искать приключений со "стандартными потоками"? С QThread возможно ответят 10 человек т.к. знают и работают с этим, а с std::thread - ну может один. И что там хорошего в std::thread?
Код:
std::thread BackGroundTH{&MainWindow::on_BACKgroundChange,this};
BackGroundTH.detach();

std::thread MoveLineTH{&MainWindow::Line_Move,this};
MoveLineTH.detach();
Так Вы запустили нитки для одноразовой работы - и теперь должны сами возюкаться как организовать их ожидание. Зачем если QThread это делает по дефаулту ?

И в любом случае святая правда что хватать UI из НЕ главной нитки - НИЗЗЯ!

Тогда не могли бы вы подсказать, в каком мне направлении копать, что бы все работало нормально?!
Перейти на QThread и задействовать слот/сигнал
Пробывал сделать как вы рекомендовали, но я не как не могу добится бесконечного цикла с использованием QThread, то ли я не правильно что то делаю, то ли у меня создается новый поток, а главный просто виснет, это первое. А второе если использовать сигнал/слоты приложение то работает, но у него нету того быстродействия которое нужно, явно видно, что приложение подвисает. Как мне решить эту проблему без потери производительности?! Возможно есть еще какие то средства которые помогу решить эту задачу?!


Название: Re: Стандартные потоки C++ в Qt
Отправлено: Igors от Апрель 28, 2017, 12:12
Цитированием не злоупотребляйте, отвечаете на последнюю строку - ее и цитируйте, или вообще ничего если и так ясно о чем речь. Давайте форум не захламлять
Пробывал сделать как вы рекомендовали, но я не как не могу добится бесконечного цикла с использованием QThread, то ли я не правильно что то делаю, то ли у меня создается новый поток, а главный просто виснет, это первое. А второе если использовать сигнал/слоты приложение то работает, но у него нету того быстродействия которое нужно, явно видно, что приложение подвисает. Как мне решить эту проблему без потери производительности?! Возможно есть еще какие то средства которые помогу решить эту задачу?!
Здесь однозначно: плохо пробОвали. Напр как там можно НЕ добиться бесконечного цикла - хз. Выкладывайте Ваши попытки с QThread (с учетом сказанного выше), думаю тогда Вам быстро помогут


Название: Re: Стандартные потоки C++ в Qt
Отправлено: SydoQQ от Май 02, 2017, 10:46
Всем спасибо, кто принимал участие в обсуждении этой темы. Добился требуемого результат с использованием контекста рисования, без потери производительности, кому будет интересен код, могу скинуть. Считаю что тема может быть закрыта.