Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: rudolfninja от Апрель 09, 2014, 16:07



Название: Выполнение метода класса в новом потоке.
Отправлено: rudolfninja от Апрель 09, 2014, 16:07
Доброго времени суток. Вопрос может показаться простым\глупым\странным (нужное подчеркнуть), но я, прочитав несколько статей по поводу QThread, так и не совсем понял ответ на него.
Ситуация такая: есть главный поток - UI, у него есть объект класса cpu. В cpu настраиваются регистры, флаги, вбивается программа в память и потом она выполняется. Так вот, надо сделать, чтоб она (программа из памяти cpu) выполнялась в отдельном потоке, чтоб была возможность работать с UI (на случай, если в cpu программа с бесконечным циклом). При этом при все, при завершении выполнения программы из cpu, объект cpu не должен уничтожаться. Он должен ждать пока в него введут новую программу и запустят.
Так вот вопрос в чем: достаточно ли для этого будет просто унаследовать класс cpu от QThread и метод run() перегрузить таким образом, чтоб в нем выполнялась программа, введенная в память процессора? При завершении программы (из памяти процессора) просто убивается процесс ее выполнения, а при повторном запуске программы он снова должен создаваться.
Спасибо.


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: OKTA от Апрель 09, 2014, 16:17
Можно, но так делать не рекомендуется и это крайне неудобно, если помимо простого выполнения код в созданном потоке должен обмениваться данными с другими объектами в других потоках. Проще сделать класс-обертку, в котором будет создаваться QThread и ваш cpu. Cpu при этом перемещается в созданный поток через movetothread и через класс-обертку с помощью сигналов обеспечиваются нужные взаимодействия. Я бы делал так  :)


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: rudolfninja от Апрель 09, 2014, 16:27
если помимо простого выполнения код в созданном потоке должен обмениваться данными с другими объектами в других потоках.
Сам cpu не обязательно кидать в новый поток, он может быть в одном потоке с UI, а вот метод execute() у cpu должен работать в новом потоке. В этом методе будут читаться данные из регистров и памяти cpu, и записываться данные в регистры и память. Получается, что все манипуляции с данными (на время выполнения программы из памяти cpu) будут выполняться в пределах объекта cpu. Хотя программа в память будет вводится из потока с UI.

Проще сделать класс-обертку, в котором будет создаваться QThread и ваш cpu. Cpu при этом перемещается в созданный поток через movetothread и через класс-обертку с помощью сигналов обеспечиваются нужные взаимодействия. Я бы делал так  :)

А можно какой-нибудь простенький пример этого приема?


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: OKTA от Апрель 09, 2014, 16:30
Если просто метод, то почитайте вот это  :) http://qt-project.org/doc/qt-4.8/qtconcurrentrun.html


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: rudolfninja от Апрель 09, 2014, 16:42
Насколько я понял, чтоб использовать QtConcurrentRun, то у меня этот метод класса должен быть статическим?
А если использовать метод, который вы предложили ранее, то UI и cpu будут обмениваться данными через эту обертку, так?


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: OKTA от Апрель 09, 2014, 16:43
Насколько я понял, чтоб использовать QtConcurrentRun, то у меня этот метод класса должен быть статическим?
А если использовать метод, который вы предложили ранее, то UI и cpu будут обмениваться данными через эту обертку, так?

Да нет, не должен он быть статическим. С чего вы взяли?
Да, через обертку.


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: rudolfninja от Апрель 09, 2014, 16:49
Ну, чтоб знать адрес функции на момент компиляции. По крайней мере, Win32Api функции CreateThread надо передавать статический метод класса.
Нашел на форуме тему с моей проблемой: http://www.prog.org.ru/topic_19310_0.html (http://www.prog.org.ru/topic_19310_0.html). Буду пробовать сделать таким же образом. Спасибо за помощь.


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: rudolfninja от Апрель 09, 2014, 17:48
Сделал так. В UI вбиваю программу, которая будет в cpu выполняться в бесконечном цикле
Код:
void MainWindow::on_start_cx_button_clicked()
{
    _cpu.write_byte_to_memory(CS, 0x100, 0xBA);
    _cpu.write_byte_to_memory(CS, 0x101, 0xFB);
    _cpu.write_byte_to_memory(CS, 0x102, 0xFF);
    _cpu.write_byte_to_memory(CS, 0x103, 0xEC);
    _cpu.write_byte_to_memory(CS, 0x104, 0xBA);
    _cpu.write_byte_to_memory(CS, 0x105, 0xFA);
    _cpu.write_byte_to_memory(CS, 0x106, 0xFF);
    _cpu.write_byte_to_memory(CS, 0x107, 0xEE);
    _cpu.write_byte_to_memory(CS, 0x108, 0xEB);
    _cpu.write_byte_to_memory(CS, 0x109, 0xF6);
    _cpu._registers[IP] = 0x100;
    _cpu._stop_address = 0x10A;

    _cpu.run();
}

В cpu:
Код:
void intel8086::run()
{

    QtConcurrent::run(this, &intel8086::execute);
}

void intel8086::execute()
{
    while(_registers[IP] <= _stop_address){
        step();
    }
}

Однако программа зависает и падает на функции void intel8086::run(). Не подскажете, в чем может быть ошибка?
Тут run выполняет бесконечный цикл и программа валится как только первая итерация проходит.


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: gil9red от Апрель 09, 2014, 18:15
А что в step() происходит?


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: Old от Апрель 09, 2014, 18:26
Если посмотреть на код из on_start_cx_button_clicked, то наверное все таки так:
Код
C++ (Qt)
void intel8086::execute()
{
   while(_registers[IP] < _stop_address){
       step();
   }
}
 


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: rudolfninja от Апрель 09, 2014, 18:52
А что в step() происходит?
Step - очень большая и сложная функция. По сути, моя программа - эмулятор микропроцессора. В нее вводится машинный код ассемблеровских команд и cpu их выполняет. В функции степ происходит расшифровка кода команды, определяются операнды и команда и выполняется команда в соответствии с полученным кодом.

Если посмотреть на код из on_start_cx_button_clicked, то наверное все таки так:
Код
C++ (Qt)
void intel8086::execute()
{
   while(_registers[IP] < _stop_address){
       step();
   }
}
 

Вряд ли. Я просто в этом методе ввел команду в память процессора. Потом она будет вводится по другому, это я сейчас для теста так сделал.
Причем в консольном приложении эта программа (вбитая в cpu) отлично отрабатывает в бесконечном цикле.


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: Old от Апрель 09, 2014, 18:58
Я не говорю, что это причина падения. Я просто уточнил, что при указанных вами исходных данных по адресу 0x10A уже не будет кода, а step будет вызван.


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: rudolfninja от Апрель 09, 2014, 19:01
Согласен, исправил. Спасибо. Но, к сожалению, это не решение проблемы.


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: Old от Апрель 09, 2014, 19:05
Но, к сожалению, это не решение проблемы.
Скажите, я правильно понимаю, что так все будет работать в одном потоке?
Код
C++ (Qt)
void intel8086::run()
{
   execute();
}
 
void intel8086::execute()
{
   while(_registers[IP] <= _stop_address){
       step();
   }
}


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: rudolfninja от Апрель 09, 2014, 19:08
Да. В однопоточном консольном приложении это все отлично отрабатывает.
Ребят, понял в чем проблема. Проблема во взаимодействии с UI. Буду сейчас смотреть где проблема.
Пока что вопрос есть, а как убить выполнение этой функции?


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: Old от Апрель 09, 2014, 19:10
Да. В однопоточном консольном приложении это все отлично отрабатывает.
А после запуска execute в отдельном потоке, в главном потоке происходит работа с объектом _cpu?


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: rudolfninja от Апрель 09, 2014, 19:25
Да. Там тяжелое взаимодействие. Собственно, из-за этого и валилась программа.
У меня эта программа (вбитая в память cpu) в бесконечном цикле читает состояние чекбокса и выводит его в QLabel.
Чекбокс "соединен" с адресом 0xfffa памяти cpu. Когда чекбокс помечен, по этому адресу пишется единица, когда не помечен - ноль.
Аналогичным образом label "соединен" по адресу 0xfffb. Программа из памяти процессора в бесконечном цикле читает то, что по адресу 0xfffa  и кидает по адресу 0xfffb. QLabel динамически создан в cpu и отображен на форме. При записи по адресу 0xfffb этот QLabel обновляется и изменение должно отобразиться на форме.
Вот на моменте, когда я пытаюсь изменить этот label программа и валиться


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: Old от Апрель 09, 2014, 19:29
Вот на моменте, когда я пытаюсь изменить этот label программа и валиться
Ну так нельзя работать с GUI из другого потока. Или работайте в главном потоке или развязывайте взаимодействие через очередь событий, например, сигналами.


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: rudolfninja от Апрель 09, 2014, 19:56
Ребят, всем спасибо. Вроде разобрался.
Теперь вопрос, как убить выполнение этой функции?


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: Old от Апрель 09, 2014, 20:00
Теперь вопрос, как убить выполнение этой функции?
Как всегда. :)
Добавьте в вашу функцию проверку некоего флага и при его изменении выходите из функции.


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: rudolfninja от Апрель 09, 2014, 21:27
QtConcurrent::run возвращает объект QFuture, у него есть метод cancel, который, вроде как, убивает поток, в котором выполняется этот метод. Его можно использовать, чтоб убить функцию или только флажком каким-нибудь?


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: Old от Апрель 09, 2014, 21:29
QtConcurrent::run возвращает объект QFuture, у него есть метод cancel, который, вроде как, убивает поток, в котором выполняется этот метод. Его можно использовать, чтоб убить функцию или только флажком каким-нибудь?
Убивать нитки чревато, лучше их завершать.


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: rudolfninja от Апрель 09, 2014, 21:43
Так а как завершить, если программа в процессоре работает в бесконечном цикле? И флаг тоже никакой нельзя проверить, так как программа (выполняемая cpu) пишется пользователем и заставлять его делать проверку флажка по какому-то адресу - не вариант совсем.


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: Old от Апрель 09, 2014, 21:48
Так а как завершить, если программа в процессоре работает в бесконечном цикле? И флаг тоже никакой нельзя проверить, так как программа (выполняемая cpu) пишется пользователем и заставлять его делать проверку флажка по какому-то адресу - не вариант совсем.
Пользователя просить не надо. :)
Вот на примере вашего кода:
Код
C++ (Qt)
void intel8086::execute()
{
   while( _running && _registers[IP] < _stop_address){
       step();
   }
}
 
void intel8086::stop()
{
   _running = false;
}
 

Как только нужно завершить функцию execute, выполняемую в отдельном потоке, вызываете _cpu.stop()


Название: Re: Выполнение метода класса в новом потоке.
Отправлено: rudolfninja от Апрель 09, 2014, 21:50
Ну да, спасибо. Это, действительно, хороший вариант.
Спасибо, большое, всем, кто ответил. Проблему свою решил.