пробую написать простенькую многопоточную программку, но она выдает сообщение об ошибке
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 22fe34. Receiver '' (of type 'QProgressBar') was created in thread 5d70b8", file kernel\qcoreapplication.cpp, line 347
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 22fe28. Receiver '' (of type 'QProgressBar') was created in thread 5d70b8", file kernel\qcoreapplication.cpp, line 347
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.
вот пример кода
#include <QApplication>
#include <QLabel>
#include <QtGui>
#include "thread.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QProgressBar *bar1 = new QProgressBar;
QProgressBar *bar2 = new QProgressBar;
MyThread thread1(bar1);
MyThread thread2(bar2);
thread1.start(QThread::NormalPriority);
thread2.start(QThread::LowPriority);
bar1->show();
bar2->show();
return app.exec();
}
#ifndef THREAD_H
#define THREAD_H
#include <qapplication.h>
#include <qthread.h>
#include <qprogressbar.h>
#include <qgridlayout.h>
#include <qlabel.h>
// ======================================================================
class MyThread : public QThread {
QProgressBar* m_pprb;
public:
MyThread(QProgressBar* pprb) : QThread()
, m_pprb(pprb)
{
}
void run()
{
for(int i = 0; i <= 100000000; ++i) {
m_pprb->setValue(i / 1000000);
}
}
};
#endif // THREAD_H
SOURCES += main.cpp
CONFIG += qt warn_on release thread
TARGET = Threads
TEMPLATE = app
HEADERS += thread.h
m_pprb->setValue(i / 1000000);
m_pprb->setProgress(i / 1000000);
капец, разобрался почему не работает))))
у меня в файле про указано
CONFIG += qt warn_on release thread
хоть программа и работает, но все же примерно через раз вылетает, предлогая закрыть программу...
в чем может быть проблема?)
так в GUI не катит многопоточность??? а если второй поток будет выполняться выводя на экран уже в по окончанию работы ??? так нормально будет?
спасибо) буду изучать и пробывать))
мне вот интересно, а сколько потоков допустимо за раз запускать, чтобы комп не начинал пыхтеть как ошпаренный?))
т.е. если у меня двух ядерник, то лучше всего не более двух потоков использовать, я правельно понял?)))
мне бы нужно хотябы два-три потока сделать, но опять же чтобы не напрягало систему до безпредела)) но почему то все советуют, что если нет крайней необходимости во многопоточности, то ее вообще лучше изключить)) но мне бы все же хотелось чтобы моя прога была многопоточная - это интереснее будет думаю)) мне нужна скорость высокая выполнения, допустим прога должна провести за один запуск 100 циклов с целой кучей всякой хрени в них, так вот, будет бустрее если она будет выполняться в нескольких потоках или в одном?)
да, именно так. Когда обработка идет "надо сделать все", то количество потоков увеличивать имеет смысл только в н-ядерных процессорах, либо "чтобы не вешало GUI".
понятно, спасибо))
я просто чем был удивлен, скачал тут недавно программу прокси-чекер, так она 15 потоков сразу использует))) причем работает достаточно быстренько - а у меня двух ядерный бук 2,2Ггрц и оперативки 3гбайт.
а я попробывал на кьюти написать самый простенький пример из трех потоков, как комп начал вешаться, вентилятор на проце дико заревел аж))))))
здравствуйте, еще раз решил поднять тему многопоточности. по моему то что я сделал не многопоточно работает, такое ощущение что в один поток все бахает.
вот класс потока:
class Thread : public QThread
{
Q_OBJECT
public:
Thread()
{
}
void run(int i);
};
#endif // THREADS_H
void Thread::run(int i)
{
QString sait = list[i]; \\"http://google.ru", "http://ya.ru", "http://mail.ru", "http://google.ru" и так далее
curl->load(sait)->exec(); //Это загрузка гугла через курл
finished();
}
int mainWindow::Start()
{
a = list.length();
Thread thread;
for(int i=0; i<a; i++)
{
thread.run(i);
thread.start();
}
return 0;
}
thread.run(i);
а как можно?)
я вот сделал вот так сейчас
void mainWindow::Start()
{
Thread thread;
list1 << "1" << "2" << "3"<< "4" << "5" << "6"<< "7" << "8" << "9"<< "10" << "11" << "12"<< "13" << "14" << "15";
list2 << "101" << "102" << "103"<< "104" << "105" << "106"<< "107" << "108" << "109"<< "110" << "111" << "112"<< "113" << "114" << "115";
QString q1;
QString q2;
for(int i=0; i<14; i++)
{
q1 = list1[i];
q2 = list2[i];
thread.run(q1, q2);
thread.start();
}
}
void Thread::run(QString str1, QString str2)
{
qDebug() << str1 << str2;
}
void mainWindow::Start()
{
Thread thread;
list1 << "1" << "2" << "3"<< "4" << "5" << "6"<< "7" << "8" << "9"<< "10" << "11" << "12"<< "13" << "14" << "15";
list2 << "101" << "102" << "103"<< "104" << "105" << "106"<< "107" << "108" << "109"<< "110" << "111" << "112"<< "113" << "114" << "115";
for(int i=0; i<14; i++)
{
q1 = list1[i];
q2 = list2[i];
thread.run();
thread.start();
}
}
void Thread::run()
{
makeFunktion(q1, q2);
}
void Thread::makeFunktion(QString str1, QString str2)
{
qDebug() << str1 << str2;
}
for(int i=0; i<14; i++)
{
q1 = list1[i];
q2 = list2[i];
thread.run();
thread.start();
Sleep(100);
}
eldar85, ты должен вызывать только Thread::start(). Он, в свою очередь, вызывает run()
Под "переопределить метод" понимается, создать в наследнике точно такую же функцию, не изменяя её сигнатуры (имени и типа аргументов)
но мне нужно чтобы каждый поток работал с функцией makeFunktion(QString q1, QString q2) ; но с разными переменными, например мне нужно передать в функцию makeFunktion(QString q1, QString q2) ; два параметра, но в каждом потоке они должны быть разными. значит run() вызывать вообще не нужно, хммм))) ок, буду пробывать, потому что так как я сделал прога вылетает))) спасибо за совет, попробую отпишусь)
но в метод run()
{
//я же могу что угодно накидать для выполнения? правильно?
}
а я правильно в цикле потоки вызываю если оттуда метод run() убрать из цикла? или каждый поток должен называться по разному???
for(int i=0; i<8; i++)
{
thread.start();
}
void mainWindow::Start()
{
Thread thread;
list1 << "1" << "2" << "3"<< "4" << "5" << "6"<< "7" << "8" << "9"<< "10" << "11" << "12"<< "13" << "14" << "15";
list2 << "101" << "102" << "103"<< "104" << "105" << "106"<< "107" << "108" << "109"<< "110" << "111" << "112"<< "113" << "114" << "115";
for(int i=0; i<5; i++)
{
thread.start();
}
}
void Thread::run()
{
makeFunktion(q1, q2);
}
void Thread::makeFunktion(QString str1, QString str2)
{
Sleep(1000);
qDebug() << q1 << q2;
}
все равно что то не то получается... если я запускаю в цикле запуск потоков, то (на мой взгляд судя по сообщению в консоли QThread: Destroyed while thread is still running запускаетс один и тот же поток столько раз сколько я поставил в цикле
) происходит вылет программы и выводится результат лишь последнего потока.
void mainWindow::Start()
{
Thread thread;
list1 << "1" << "2" << "3"<< "4" << "5" << "6"<< "7" << "8" << "9"<< "10" << "11" << "12"<< "13" << "14" << "15";
list2 << "101" << "102" << "103"<< "104" << "105" << "106"<< "107" << "108" << "109"<< "110" << "111" << "112"<< "113" << "114" << "115";
q3 = text1->toPlainText();
qDebug() << q3;
for(int i=0; i<5; i++)
{
q1 = list1[i];
q2 = list2[i];
thread.start();
}
text->append(q3);
}
void Thread::run()
{
makeFunktion(q1, q2);
}
void Thread::makeFunktion(QString str1, QString str2)
{
Sleep(1000);
qDebug() << q1 << q3;
// qDebug() << str1 << str2;
}
вообще ничего не пойму, как же мне хотябы 5 потоков в одно время то запустить??? чтобы они выполняли одну функцию, но с с двумя разными перемеными QString????
Тема больше для раздела "Qt Ввод/Вывод, Сеть. Межпроцессное взаимодействие".
eldar85, читай документацию, ты задаешь такие вопросы, ответ на которые можно получить за 10 минут просто посмотрев примеры и почитав описание к классу QThread.
так вот именно что про QThread написано всего то:
всего один пример
class MyThread : public QThread
{
public:
void run();
};
void MyThread::run()
{
QTcpSocket socket;
// connect QTcpSocket's signals somewhere meaningful
...
socket.connectToHost(hostName, portNumber);
exec();
}
создаёшь десять экземпляров класса MyThread, всем командуешь run(), вот тебе 10 потоков
спасибо)
вновь взялся за потоки, выяснил как их запускать в цикле:
Thread thread[10];
for( int n = 0; n < 4; n++)
{
thread[n].start();
Sleep(10);
}
for( int n = 0; n < 4; n++)
{
thread[n].wait();
Sleep(10);
}
void Thread::run()
{
makeFunktion("1", "2");
Sleep(10000);
makeFunktion("3", "4");
}
Sleep(10); - это же, вроде, 10мс
А разве основной поток может завершиться, пока выполняются дочерние ? Кроме того, если завершить основной, то дочерние сдохнут сразу
for( int n = 0; n < 4; n++)
{
thread[n].wait();
Sleep(10);
}
если не сделать
thread[n].wait();
thread[n].wait();
убрав второй цикл все потоки тут же убиваются после того как закончиться первый цикл и все, получается просто ничего не работает. если убрать из ран() ожидание в 10 сек, то конечно все почти нормально, и то в консоли пишет что потоки убиты до того как они были закончены.
а если у меня в ран будет что то очень долго выполняться то поток просто будет убит ничего не сделав...
большое вам спасибо, наконец то получилось)))
вот код
Thread *thread = new Thread[10];
for( int n = 0; n < 10; n++)
{
thread[n].start();
}
все же сложность одна осталась с многопоточностью, я никак не пойму как можно сделать так чтобы метод ран использовал главное окно для вывода на него информации:
сделал функцию для вывода на экран vivod(), в функции knopka() по нажатию кнопки запускается процесс, получается метод run() это другой класс Thread, а остальные все объекты относятся к классу mainWidow, возможно очень глупый вопрос, согласен, но я уже перерыл много инфы и что только не попробывал и никак не дойдет как же сделать из метода run() запуск функции vivod().
и пробывал vivod() сделать функцией другом в классе Thread friend void mainWindow::vivod(); но реакции ноль...
помогите разобраться, ну никак не разберусь...
void mainWindow::vivod(QString str)
{
ui->textEdit->append(str);
}
void mainWidoww::knopka()
{
Thread *thread = new Thread[10];
for(g=0; g<10; g++)
{
thread[g].start();
Sleep(100);
}
}
//===============================================================================
void Thread::run()
{
//вот тут как поместить функцию vivod() ?????
qDebug() << "gggg";
}
void MyThread::run()
{
QTcpSocket socket;
// connect QTcpSocket's signals somewhere meaningful
...
socket.connectToHost(hostName, portNumber);
exec();
}
void Thread::run()
{
mainWindow main;
main.vivod("fff");
qDebug() << "gggg";
}
да я тоже думал об этом, только не совсем разберусь как это сделать...
получается в главном окне слот нужно сделать pablic slots???
и еще впрос, какой сигнал кидать в потоке??? я сильно путаюсь еще в сигналах...
eldar85, там вроде пофиг, приватный он или открытый, точно не помню.
А путаешься в них зря - типы функций сигнала и слота должны быть одинаковые, вот и всё
Перед запуском потока нужно connect его сигнал со слотом главного окна
(С сигналами тут вообще многое упрощается В студии приходится передавать в поток указатель на внешний объект)
вот создал я паблик слот в главном окне
public slots:
void vivod(QString str);
void mainWindow::vivod(QString str)
{
ui->textEdit->append(str);
}
void Thread::run()
{
connect() //вот тут я не пойму что именно будет давать сигналы моему слоту
qDebug() << "gggg";
}
нет, как-то вот так
class MyThread: .... (главное, что public QObject)
{
Q_OBJECT
public signals:
void vivod(QString str);
public://<<<
void run();
};
class CMainWin: .... (главное, что public QObject)
{
Q_OBJECT
public slots:
void vivod(QString str);
public://<<<
void knopka();
};
void CMainWin::knopka()
{
Thread *thread = new MyThread[10];
for(g=0; g<10; g++)
{
connect(&MyThread[g],MyThread.vivod , this, vivod);
thread[g].start();
Sleep(100);
}
}
void MyThread::run()
{
emit vivod("12345");
}
большое спасибо, сейчас буду пробывать, потом отпишусь))))
нет, получается вообще чет непонятное, он на сигнал vivod() из Thread ругается теперь
first defined heremultiple definition of `Thread::vivod1(QString)'
multiple definition of `Thread::run()'
eldar85, я не знаю иерархию твоих инклудов. Прицепил бы проект ? )
спасибо тебе за совет, все получилось))))))))))))))))
ошибка была в твоем коде лишь в том что ты метод run() сделал как сигнал, его нужно просто объявлять как обычную функцию, а остальное все отлично, еще раз спасибо, наконец то хоть что то прояснилось, да еще и почитал про сигналы со слотами побольше... я как то им мало придавал значения... это было моей глупостью)))
Ага, вижу косяк, спецификатор доступа не переопределил
public signals:
void vivod(QString str);
public://<<<
void run();
все работает отлично, вот только еще с одним бы разобраться, допустим я запустил десять потоков в таком плане
void mainWindow::vivod(QString str)
{
ui->textEdit->append(str);
}
void mainWindow::knopka()
{
Thread *thread = new Thread[10];
for(g=0; g<10; g++)
{
connect(&thread[g],SIGNAL(vivod1(QString)), this, SLOT(vivod(QString)));
WOW = "good ";
WOW.append(QString::number(g));
thread[g].start();
Sleep(1000);
}
}
//===============================================================================
void Thread::run()
{
emit vivod1(WOW);
qDebug() << "gggg";
}
попробуй processEvents()
void Thread::run()
{
emit vivod1(WOW);
qDebug() << "gggg";//<<ещё бы штамп времени сюда бацнуть )))
/*QApplication::*/processEvents(); //<<< обработать сообщения
}
eldar85, ты всё же сделай примитивный проект, окно с кнопкой и меткой, при нажатии на кнопку в метку помести текст "начали", затем запускай потоки, которые что-то будут делать, например большие циклы. По завершении потоков выводи в метку "закончили".
Если с таким приложением будут проблемы - выкладывай в форум.
а все, я разобрался почему))) дело было в том что я ставил ожидание в секунду в цикле запуска потоков, в итоге главное окно ждало когда закончиться цикл и только после этого обновляло окошко ... если ожидание из цикла убрать и поставить в метод run() то тогда все cool...
да проект то и так не сложный, примерно так как вы и сказали, одна кнопка, одно текстовое поле и класс для потоков...
главное что я понял что задерживало вывод в тектовое поле, это долбынный цикл)) и поставил за одно в него qApp->procecEvent(): вот и все))
большое спасибо за помощ))
Вообще, чтобы небыло подобных вопросов о межпроцессном взаимодействии, уясни одну вещь: каждый поток выполняется в своем пространстве и со своей памятью.
Чтобы изменить ЛЮБЫЕ данные ЛЮБОГО потока твоей аппликухи, ты должен использовать ПОТОКОБЕЗОПАСНЫЕ методы.
Это касается не только кути фреймворка. Это стандарт.
Так вот, для тебя было бы проще описать в классе главного окна слот, который бы принимал данные от потока, а в потоке описать сигнал(окончания действия, к примеру), который будет вызываться только по окончании работы и внутренней подготовки данных.
Далее, при создании потока ты будешь делать connect(thread, SIGNAL(метод_который_описан_как_сигнал(record *)), widget, SLOT(слот_описанный_тобой_для_компонента_или _формы(recod *));
обрати внимание, что слот и сигнал имеют в параметре одинаковый тип данных(!).
А далее, в слоте уже делай с данными все, что пожелаешь. Можешь даже уничтожить, не читая
Это называется потокобезопасное программирование, без применения всяких вытесняющих технологий )
Только помни, что данные, которые ты передаешь между потоками должны быть созданы в куче, а не в стеке. То есть
record * rec = new record();
delete rec;
Пардон, неправильно выразился
QtConcurrent - подобных библиотек.
Я согласен, что метод мной приведенный работает далеко не всегда и, все ж таки, придется юзать мьютексы и прочие прелести тредов, но то, что я написал, хотя бы, даст пинка мысли )
Начало. Ато человек вконец запутался, как я посмотрел )
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)