Russian Qt Forum
Ноябрь 22, 2024, 18:08 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Объясните! ) Как тело функции запускается несколько раз в одном и том же потоке  (Прочитано 5179 раз)
r2d2u2
Гость
« : Ноябрь 10, 2010, 01:46 »

В общем есть Объект класса унаследованного от QThread.
Дергаем метод Start() у этого объекта несколько раз подряд.
Исполнение этого метода запускается в отдельном потоке. Несколько раз. Подряд. Причем следующий вызов не ожидает завершения предыдущего.
При этом когда этот метод запускается в то время когда выполняется исполнение предыдущего вызова, !все в том же потоке! то предыдущий вызов никуда не девается а как бы попадает в стек,
и ждет пока завершится последний вызов потом возобновляется.

Вот классы чтобы самим не писать соберите консольное приложение и потыкайте кнопкой несколько раз: у меня вывод вот такой:

ThreadObject::ThreadObject():  0x9c 0
ThreadObject::run():  0x4a0 0
ThreadObject::StartTimer():  0x4a0 0
ThreadObject::StartTimer():  0x4a0 1
ThreadObject::StartTimer():  0x4a0 2
ThreadObject::StartTimer(): stop 0x4a0 3
ThreadObject::StartTimer(): stop 0x4a0 3
ThreadObject::StartTimer(): stop 0x4a0 3


class ThreadObject: public QThread
{
  Q_OBJECT
public:
  ThreadObject();
  virtual ~ThreadObject();
public slots:
  void Start();
public:
  void run();
  int Var;
};


ThreadObject::ThreadObject()
{
  moveToThread(this);
  Var = 0;
  qDebug() << "ThreadObject::ThreadObject(): " << currentThreadId() << Var;
}

ThreadObject::~ThreadObject()
{
  quit();
  wait();
}
void ThreadObject::run()
{
  qDebug() << "ThreadObject::run(): " << currentThreadId() << Var;
  exec();
}

void ThreadObject::Start()
{
  qDebug() << "ThreadObject::StartTimer(): " << currentThreadId() << Var;
  ++Var;
  for (qint64 i = 0; i < 500000; ++i)
  {
    QCoreApplication::processEvents(QEventLoop::AllEvents, 1);
  }
  qDebug() << "ThreadObject::StartTimer(): stop" << currentThreadId() << Var;
}


class MyWidget: public QWidget
{
  Q_OBJECT
public:
  MyWidget(QWidget* parent = 0);
  void Create();
  void Layout();
  void Connect();
  void StartThread();
private:
  QPushButton* Button;
  ThreadObject TheThreadObject;
};

MyWidget::MyWidget(QWidget* parent /*= 0*/)
 : QWidget(parent)
{
  Create();
  Layout();
  Connect();
  StartThread();
}

void MyWidget::Create()
{
  Button = new QPushButton("QPush button");
}

void MyWidget::Layout()
{
  QHBoxLayout* mainLayout = new QHBoxLayout();
  mainLayout->addWidget(Button);
  setLayout(mainLayout);
}

void MyWidget::Connect()
{
  connect(Button, SIGNAL(clicked()), &TheThreadObject, SLOT(Start()));
}

void MyWidget::StartThread()
{
  TheThreadObject.start();
}


ну и main


int main(int argc, char **argv)
{
  setlocale(LC_CTYPE, "");

  bool useGUI = true;
  QApplication app(argc, argv, useGUI);
 
  MyWidget mWidget;
  mWidget.show();
 
  return app.exec();
}

Есть какие либо мысли и соображения?
Если вызвать метод Start() первый раз, начнет выполняться цикл в потоке TH01, и к примеру счетчик i дойдет до 1024.
Потом мы дергаем это метод Start() второй раз, и он запускается снова в потоке TH01! и счетчик начинает считать снова с нуля.
НО!
когда после второго вызова счетчик доходит до предела, выход из метода не происход а возобновляется работа счетчика запущенного при вызове метода в первый раз, т.ею начинается дальше счет с 1024.
Кто нить может объяснить как такое может быть? ) Понятное дело что там в теле цикла стоит вызов QCoreApplication::processEvents(QEventLoop::AllEvents, 1); который обеспечивает обработку событий в том числе обрабатывает обработку события на второй вызов этого метода Start() в то время как предыдущий вызов еще не завершился. Но как смешивается работа циклов непонятно такое ощущение, что при следующем вызове, текущий цикл помещается куда то в стек откуда потом вытаскивается.

кстати QCoreApplication::processEvents(QEventLoop::AllEvents, 1);  вызывается внутри функции void QTest::qWait ( int ms ), так что если вы вставите себе этот qWait  в теле функции f()работающей в отдельном потоке то при вызове qWait внутри f() она пропусти все события-вызовы f() и ваша f() вызовится несколько раз в одном потоке, и если так мьютекс был рекурсивный то беда! _ 
Записан
BlackTass
Гость
« Ответ #1 : Ноябрь 10, 2010, 02:14 »

По моему все вполне логично Улыбающийся метод запускается еще раз с начала во время процессЕвентс. Когда он доходит до конца процессЕвентс возвращается к выполнению предыдущего запуска этого метода (из которого был вызван этот самый процессЕвентс)
Записан
DmP
Гость
« Ответ #2 : Ноябрь 10, 2010, 12:05 »

В общем есть Объект класса унаследованного от QThread.
Дергаем метод Start() у этого объекта несколько раз подряд.
Зачем его дергать несколько раз подряд?

Исполнение этого метода запускается в отдельном потоке. Несколько раз. Подряд. Причем следующий вызов не ожидает завершения предыдущего.
В отдельном ли?
Записан
r2d2u2
Гость
« Ответ #3 : Ноябрь 10, 2010, 20:01 »

По моему все вполне логично Улыбающийся метод запускается еще раз с начала во время процессЕвентс. Когда он доходит до конца процессЕвентс возвращается к выполнению предыдущего запуска этого метода (из которого был вызван этот самый процессЕвентс)

вообщето да, получается вроде рекурсивного вызова себя самой только почему переменная Var как бы разделяется всеми рекурсивными вызовами и увеличивается при каждом вызове а цикл начинается с начала.  Улыбающийся
Записан
r2d2u2
Гость
« Ответ #4 : Ноябрь 10, 2010, 20:12 »

В общем есть Объект класса унаследованного от QThread.
Дергаем метод Start() у этого объекта несколько раз подряд.
Зачем его дергать несколько раз подряд?

Исполнение этого метода запускается в отдельном потоке. Несколько раз. Подряд. Причем следующий вызов не ожидает завершения предыдущего.
В отдельном ли?

Зачем дергать несколько раз подряд? Ну к примеру эта функция вызывается другими потоками и может так получится что она вызовется несколько раз подряд. Это в общем на конкретные названия и смысл смотреть не нужно. Это пример.

А запускается действительно в отдельном. Я и сам не пойму почему так получается. Если в конструкторе ThreadObject() вызвать moveToThread(this); то вызов ThreadObject::Start() запускается в отельном потоке. Если в конструкторе не вызывать moveToThread(this) то вызов ThreadObject::Start()  запускается в том же потоке откуда вызывается. Вот тоже непонятно почему?
Допустим конструктор ThreadObject() вызывается в главном потоке, и сам объект ThreadObject принадлежит главному потоку, и если в конструкторе вызвать moveToThread(this); то по идее это есть "перемещение" объекта ThreadObject в свой же главный поток. т.е. обработка событий по вызову слотов этого объекта будет осуществляться в главном потоке, по идее смысла от этого нет никакого как мне кажется, но после этого методы объекта ThreadObject вызываются в созданном этим объектом потоке. Вот как понять?
Записан
BRE
Гость
« Ответ #5 : Ноябрь 10, 2010, 20:21 »

А ты по форуму поищи темы по moveToThread, уже несколько раз обсуждали, что делает вышеуказанная конструкция и про типы connect, и про очереди сообщений...
Записан
DmP
Гость
« Ответ #6 : Ноябрь 10, 2010, 20:42 »

А запускается действительно в отдельном. Я и сам не пойму почему так получается. Если в конструкторе ThreadObject() вызвать moveToThread(this); то вызов ThreadObject::Start() запускается в отельном потоке. Если в конструкторе не вызывать moveToThread(this) то вызов ThreadObject::Start()  запускается в том же потоке откуда вызывается. Вот тоже непонятно почему?
Допустим конструктор ThreadObject() вызывается в главном потоке, и сам объект ThreadObject принадлежит главному потоку, и если в конструкторе вызвать moveToThread(this); то по идее это есть "перемещение" объекта ThreadObject в свой же главный поток. т.е. обработка событий по вызову слотов этого объекта будет осуществляться в главном потоке, по идее смысла от этого нет никакого как мне кажется, но после этого методы объекта ThreadObject вызываются в созданном этим объектом потоке. Вот как понять?
На самом деле тут все просто.
moveToThread(this) - приписывает объект потока в обработчик потока (как и говорится в документации).
При каждом нажатии на кнопку, сигнал помещается в очередь обработчика потока (а не вызывается напрямую, так как потоки разные).
Первый раз ThreadObject::Start() вызывается обработчиком событий потока, который запущен в void ThreadObject::run() через exec().
Все последующие разы ThreadObject::Start() вызывает сам себя, передавая управление обработчику событий через QCoreApplication::processEvents().
Записан
r2d2u2
Гость
« Ответ #7 : Ноябрь 10, 2010, 22:08 »

DmP сапасиба!  Веселый
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.052 секунд. Запросов: 21.