Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: demaker от Май 30, 2017, 23:34



Название: приоритеты
Отправлено: demaker от Май 30, 2017, 23:34
Скажите, возможно ли дать родительскому
потоку (GUI) более низкиий приоритет чем дочернему?
Если да, то не могли бы привести пример как это сделать.
Сасибо!



Название: Re: приоритеты
Отправлено: ksk- от Май 31, 2017, 05:17
http://doc.qt.io/qt-4.8/qthread.html#setPriority (http://doc.qt.io/qt-4.8/qthread.html#setPriority)
Разве нет?


Название: Re: приоритеты
Отправлено: demaker от Май 31, 2017, 10:21
http://doc.qt.io/qt-4.8/qthread.html#setPriority (http://doc.qt.io/qt-4.8/qthread.html#setPriority)
Разве нет?

Похоже что нет ???
Может я конечно делаю неправильно что-то.

Берем поток и инкрементируем в нем счетчик.
Отображаем значение счетчика на индикаторе два раза в секунду.
Потоки создаются и запускаются по нажатию кнопки.
Когда запускается поток, ему устанавливается приоритет.
Вот код
Код
C++ (Qt)
#include <QThread>
#include <QMutex>
#include <QDebug>
 
class Thread : public QThread
{
   Q_OBJECT
 
public:
   explicit Thread(QObject *parent = 0);
   virtual ~Thread();
 
public:
   int cnt();
   bool term();
   void setTerm(bool );
 
protected:
   void run();
 
public slots:
 
private:
   QMutex mutex_cnt;
   QMutex mutex_term;
   int m_cnt;
   bool m_term;
 
signals:
 
};
 
 
Thread::Thread(QObject *parent) :
   QThread(parent)
{
   m_cnt = 0;
   m_term = false;
}
 
Thread::~Thread()
{
}
 
void Thread::setTerm(bool val)
{
   mutex_term.lock();
   m_term = val;
   mutex_term.unlock();
}
 
bool Thread::term()
{
   mutex_term.lock();
   int val = m_term;
   mutex_term.unlock();
   return val;
}
 
int Thread::cnt()
{
   mutex_cnt.lock();
   int val = m_cnt;
   mutex_cnt.unlock();
   return val;
}
 
void Thread::run()
{
   for(;;)
   {
       msleep(2);
       if(!term())
           break;
       mutex_cnt.lock();
       m_cnt++;
       mutex_cnt.unlock();
   }
}
 
 
 
#include <QMainWindow>
#include <QTimer>
#include "thread.h"
 
namespace Ui {
   class MainWindow;
}
 
class MainWindow : public QMainWindow
{
   Q_OBJECT
 
public:
   explicit MainWindow(QWidget *parent = 0);
   ~MainWindow();
 
public slots:
   void clickedStart();
   void clickedStop();
   void updateView();
 
private:
   Ui::MainWindow *ui;
 
private:
   Thread *threadCnt1;
   Thread *threadCnt2;
 
   QTimer *timerView;
};
 
 
#include "mainwindow.h"
#include "ui_mainwindow.h"
 
MainWindow::MainWindow(QWidget *parent) :
   QMainWindow(parent),
   ui(new Ui::MainWindow)
{
   ui->setupUi(this);
 
   threadCnt1 = NULL;
   threadCnt2 = NULL;
 
   timerView = new QTimer(this);
   connect(timerView,SIGNAL(timeout()),this,SLOT(updateView()));
 
   connect(ui->pbStart,SIGNAL(clicked()),this,SLOT(clickedStart()));
   connect(ui->pbStop,SIGNAL(clicked()),this,SLOT(clickedStop()));
 
}
 
MainWindow::~MainWindow()
{
   delete ui;
   clickedStop();
}
 
void MainWindow::clickedStart()
{
   timerView->start(500);
 
   if(!threadCnt1){
       threadCnt1 = new Thread;
       threadCnt1->setTerm(true);
       threadCnt1->start(QThread::TimeCriticalPriority);
   }
 
   if(!threadCnt2){
       threadCnt2 = new Thread;
       threadCnt2->setTerm(true);
       threadCnt2->start(QThread::LowestPriority);
   }
}
 
void MainWindow::clickedStop()
{
   timerView->stop();
 
   if(threadCnt1){
       threadCnt1->setTerm(false);
       threadCnt1->quit();
       threadCnt1->wait();
       delete threadCnt1;
       threadCnt1 = NULL;
   }
 
   if(threadCnt2){
       threadCnt2->setTerm(false);
       threadCnt2->quit();
       threadCnt2->wait();
       delete threadCnt2;
       threadCnt2 = NULL;
   }
}
 
void MainWindow::updateView()
{
   ui->lcdCntThread1->display(threadCnt1->cnt());
   ui->lcdCntThread2->display(threadCnt2->cnt());
}
 
Во время раьоты программы значения счетчиков постоянно одинаковы, хотя приоритеты у потоков разные.
Может я конечно не прав,но получается что  в  Qt нельзя раздать приорететы потокам. Или это надо делать как-то по особеннолму?   


Название: Re: приоритеты
Отправлено: ksk- от Май 31, 2017, 18:23
Ну тогда придётся написать платформозависимый код.

Например:
http://www.yonch.com/tech/82-linux-thread-priority (http://www.yonch.com/tech/82-linux-thread-priority) или https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms686277(v=vs.85).aspx (https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms686277(v=vs.85).aspx)


Название: Re: приоритеты
Отправлено: demaker от Май 31, 2017, 19:56
Ну тогда придётся написать платформозависимый код.

Например:
http://www.yonch.com/tech/82-linux-thread-priority (http://www.yonch.com/tech/82-linux-thread-priority) или https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms686277(v=vs.85).aspx (https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms686277(v=vs.85).aspx)
Спасибо, попробую.


Название: Re: приоритеты
Отправлено: demaker от Июнь 01, 2017, 14:17
Ну тогда придётся написать платформозависимый код.

Например:
http://www.yonch.com/tech/82-linux-thread-priority (http://www.yonch.com/tech/82-linux-thread-priority) или https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms686277(v=vs.85).aspx (https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms686277(v=vs.85).aspx)
Спасибо, попробую.


К сожалению не помогло.
Пробовал для  Windows.
Функция  GetCurrentThread() в MainWondow и в run() потоках возвращает одинаковые значения.
Qt функция thread() возвращает разные значения указателей на потоки.
Не могу понять ??? ??? ???

Код:
Код
C++ (Qt)
MainWindow::MainWindow(QWidget *parent) :
   QMainWindow(parent),
   ui(new Ui::MainWindow)
{
   ui->setupUi(this);
 
   cnt = 0;
   threadCnt1 = NULL;
   threadCnt2 = NULL;
 
   timerView = new QTimer(this);
   connect(timerView,SIGNAL(timeout()),this,SLOT(updateView()));
 
   connect(ui->pbStart,SIGNAL(clicked()),this,SLOT(clickedStart()));
   connect(ui->pbStop,SIGNAL(clicked()),this,SLOT(clickedStop()));
 
   qDebug()<<"main thread_Qt = "<<thread();
   qDebug()<<"main thread_WINAPI = "<<GetCurrentThread();
}
 
 
void Thread::run()
{
   qDebug()<<"thread_Qt = "<<thread();
   qDebug()<<"thread_WINAPI = "<<GetCurrentThread();
   SetThreadPriority(GetCurrentThread(),m_priority);
   for(;;)
   {
       msleep(2);
       if(!term())
           break;
       mutex_cnt.lock();
       m_cnt++;
       mutex_cnt.unlock();
   }    
}
 


Название: Re: приоритеты
Отправлено: ViTech от Июнь 01, 2017, 16:43
Попробуйте убрать для начала "msleep(2);". И блокировок слишком много, потоки особо не конкурируют. Лучше сделайте пример, где потоки обращаются к одной переменной: один увеличивает её, другой уменьшает. Там должна быть заметна разница в приоритетах.


Название: Re: приоритеты
Отправлено: demaker от Июнь 01, 2017, 17:19
Попробуйте убрать для начала "msleep(2);". И блокировок слишком много, потоки особо не конкурируют. Лучше сделайте пример, где потоки обращаются к одной переменной: один увеличивает её, другой уменьшает. Там должна быть заметна разница в приоритетах.

Попробовал как Вы сказали.
Один поток работает на увеличение значения, другой поток его уменьшает.
Результат примерно такой жe - иногда проскальзывает единица на экран, потом нуль.

Вот код:
Код
C++ (Qt)
 
//Global varibles
int varible;
QMutex mutex_varible;
 
 
MainWindow::MainWindow(QWidget *parent) :
   QMainWindow(parent),
   ui(new Ui::MainWindow)
{
   ui->setupUi(this);
 
   //cnt = 0;
   varible = 0;
   threadCnt1 = NULL;
   threadCnt2 = NULL;
 
   timerView = new QTimer(this);
   connect(timerView,SIGNAL(timeout()),this,SLOT(updateView()));
 
   connect(ui->pbStart,SIGNAL(clicked()),this,SLOT(clickedStart()));
   connect(ui->pbStop,SIGNAL(clicked()),this,SLOT(clickedStop()));
 
}
 
void MainWindow::clickedStart()
{
   timerView->start(1000);
 
   if(!threadCnt1){                
#ifdef __linux__
       threadCnt1 = new Thread(sched_get_priority_max(SCHED_FIFO));
#elif __WIN32__
       threadCnt1 = new Thread(THREAD_PRIORITY_TIME_CRITICAL);
#endif
       threadCnt1->setTerm(true);
       threadCnt1->start();
   }
 
   if(!threadCnt2){
#ifdef __linux__
       threadCnt2 = new Thread(sched_get_priority_min(SCHED_FIFO));
#elif __WIN32__
       threadCnt2 = new Thread(THREAD_PRIORITY_IDLE);
#endif
       threadCnt2->setTerm(true);
       threadCnt2->start();
   }
}
 
void MainWindow::clickedStop()
{
   varible = 0;
   timerView->stop();
 
   if(threadCnt1){
       threadCnt1->setTerm(false);
       threadCnt1->quit();
       threadCnt1->wait();
       delete threadCnt1;
       threadCnt1 = NULL;
   }
 
   if(threadCnt2){
       threadCnt2->setTerm(false);
       threadCnt2->quit();
       threadCnt2->wait();
       delete threadCnt2;
       threadCnt2 = NULL;
   }
}
 
void MainWindow::updateView()
{  
   mutex_varible.lock();
   ui->lcdGUIThread->display(varible);
   mutex_varible.unlock();
}
 
void Thread::run()
{
#ifdef __linux__
   pthread_t this_thread = pthread_self();
   struct sched_param params;
   params.sched_priority = m_priority;
   pthread_setschedparam(this_thread,SCHED_FIFO,&params);
#elif __WIN32__
   qDebug()<<"thread_Qt = "<<thread();
   qDebug()<<"thread_WINAPI = "<<GetCurrentThread();
   SetThreadPriority(GetCurrentThread(),m_priority);
#endif
 
   if(m_priority == THREAD_PRIORITY_TIME_CRITICAL){
       for(;;)
       {
           msleep(2);
           if(!term())
               break;
           //mutex_cnt.lock();
           //m_cnt++;
           //mutex_cnt.unlock();
 
           //mutex_varible.lock();
           varible++;
           //mutex_varible.unlock();
       }
   }
   else if(m_priority == THREAD_PRIORITY_IDLE){
       for(;;)
       {
           msleep(2);
           if(!term())
               break;
           //mutex_cnt.lock();
           //m_cnt++;
           //mutex_cnt.unlock();
 
           //mutex_varible.lock();
           varible--;
           //mutex_varible.unlock();
 
       }
   }
}
 
 
void MainWindow::updateView()
{  
   //mutex_varible.lock();
   ui->lcdGUIThread->display(varible);
   //mutex_varible.unlock();
}
 


Название: Re: приоритеты
Отправлено: ViTech от Июнь 01, 2017, 18:31
1. Приоритет потоку нужно задавать после его старта, об этом выводится отладочное сообщение.
2. Убрать "msleep(2);", это очень большая задержка, там ещё на блокировках и выводе переменной в lcdGUIThread много времени уходит.
3. Увеличить число знаков в ui->lcdGUIThread->setDigitCount(10);

Код
C++ (Qt)
void MainWindow::clickedStart()
{
   varible = 0;
 
   timerView->start(500);
 
   if(!threadCnt1){
       threadCnt1 = new Thread();
       threadCnt1->setTerm(true);
       threadCnt1->start();
       threadCnt1->setPriority(QThread::TimeCriticalPriority);
   }
 
   if(!threadCnt2){
       threadCnt2 = new Thread();
       threadCnt2->setTerm(true);
       threadCnt2->start();
       threadCnt2->setPriority(QThread::IdlePriority);
   }
}
 
void Thread::run()
{
   if(priority() == QThread::TimeCriticalPriority){
       for(;;)
       {
           //msleep(2);
           if(!term())
               break;
           //mutex_cnt.lock();
           //m_cnt++;
           //mutex_cnt.unlock();
 
           mutex_varible.lock();
           varible++;
           mutex_varible.unlock();
       }
   }
   else if(priority() == QThread::IdlePriority){
       for(;;)
       {
           //msleep(2);
           if(!term())
               break;
           //mutex_cnt.lock();
           //m_cnt++;
           //mutex_cnt.unlock();
 
           mutex_varible.lock();
           varible--;
           mutex_varible.unlock();
       }
   }
}
 

С таким кодом у меня нормально приоритеты потоков соблюдаются.


Название: Re: приоритеты
Отправлено: demaker от Июнь 01, 2017, 19:14
1. Приоритет потоку нужно задавать после его старта, об этом выводится отладочное сообщение.
2. Убрать "msleep(2);", это очень большая задержка, там ещё на блокировках и выводе переменной в lcdGUIThread много времени уходит.
3. Увеличить число знаков в ui->lcdGUIThread->setDigitCount(10);

Код
C++ (Qt)
void MainWindow::clickedStart()
{
   varible = 0;
 
   timerView->start(500);
 
   if(!threadCnt1){
       threadCnt1 = new Thread();
       threadCnt1->setTerm(true);
       threadCnt1->start();
       threadCnt1->setPriority(QThread::TimeCriticalPriority);
   }
 
   if(!threadCnt2){
       threadCnt2 = new Thread();
       threadCnt2->setTerm(true);
       threadCnt2->start();
       threadCnt2->setPriority(QThread::IdlePriority);
   }
}
 
void Thread::run()
{
   if(priority() == QThread::TimeCriticalPriority){
       for(;;)
       {
           //msleep(2);
           if(!term())
               break;
           //mutex_cnt.lock();
           //m_cnt++;
           //mutex_cnt.unlock();
 
           mutex_varible.lock();
           varible++;
           mutex_varible.unlock();
       }
   }
   else if(priority() == QThread::IdlePriority){
       for(;;)
       {
           //msleep(2);
           if(!term())
               break;
           //mutex_cnt.lock();
           //m_cnt++;
           //mutex_cnt.unlock();
 
           mutex_varible.lock();
           varible--;
           mutex_varible.unlock();
       }
   }
}
 

С таким кодом у меня нормально приоритеты потоков соблюдаются.

Понял. Спасибо.
А поменять приоритет  потока gui так
Код:
 thread ()->setPriority (QThread::IdlePriority)
можно?
 


Название: Re: приоритеты
Отправлено: ViTech от Июнь 01, 2017, 19:21
А поменять приоритет  потока gui так
Код:
thread ()->setPriority (QThread::IdlePriority)
можно?

Можно.


Название: Re: приоритеты
Отправлено: demaker от Июнь 02, 2017, 09:59
А вот еще такой вопрос.  ::)
Почему когда у меня было два потока с разными приоритетами. У каждого потока свой инкрементный счетчик.
То разницы значений счетчиков не было, хотя мне казалось , что у потока с более высоким приоритетом
значение счетчика должно быть больше. Разве нет ??? (Или это связанно с тем что процессор не загружен.)


Название: Re: приоритеты
Отправлено: ViTech от Июнь 02, 2017, 13:38
Причины те же (п. 1, 2). Если система свободна и потоки не конкурируют, то планировщик потоков ОС может и даёт им выполняться на равных условиях, не зависимо от их приоритетов, особенно на многоядерном процессоре. И с задержкой msleep(2) вы, в некоторой степени, синхронизируете потоки. С такой задержкой каждый из них выполнится порядка 500 раз в секунду, не зависимо от приоритета. И такая задержка намного больше времени выполнения "полезного кода". Грубо говоря, изменение счётчика выполняется за несколько микросекунд, а потом он спит 2000 микросекунд. И это с блокировками. Без блокировок разница может быть ещё на порядки больше.


Название: Re: приоритеты
Отправлено: demaker от Июнь 02, 2017, 13:44
По поводу msleep.
Когда у меня его нет, то у меня отображение вообще не изменяется.


Название: Re: приоритеты
Отправлено: ViTech от Июнь 02, 2017, 14:08
Тогда компилируемый проект выкладывайте, чтобы было с чем разбираться.


Название: Re: приоритеты
Отправлено: demaker от Июнь 02, 2017, 14:30
Вот проект


Название: Re: приоритеты
Отправлено: ViTech от Июнь 02, 2017, 15:04
По поводу msleep.
Когда у меня его нет, то у меня отображение вообще не изменяется.

Отображение не изменяется, потому что не исправлен пункт 3:
Цитировать
3. Увеличить число знаков в ui->lcdGUIThread->setDigitCount(10);

lcdGUIThread офигивает от того, сколько всего может сделать современный процессор за секунду, что в 5 цифр по умолчанию не влазит, и он такие числа не отображает :).


Название: Re: приоритеты
Отправлено: demaker от Июнь 02, 2017, 15:23
По поводу msleep.
Когда у меня его нет, то у меня отображение вообще не изменяется.

Отображение не изменяется, потому что не исправлен пункт 3:
Цитировать
3. Увеличить число знаков в ui->lcdGUIThread->setDigitCount(10);

lcdGUIThread офигивает от того, сколько всего может сделать современный процессор за секунду, что в 5 цифр по умолчанию не влазит, и он такие числа не отображает :).
Спасибо.