Версия для печати темы
Форум на CrossPlatform.RU _ Qt Ввод/Вывод, Сеть. Межпроцессное взаимодействие _ Как понять что программа работает в двух потоках?
Автор: RazrFalcon 4.10.2010, 14:31
Есть простой пример из хелпа
#include <QtCore/QCoreApplication>
#include <QString>
#include "thread.h"
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyThread th, th2;
th.start();
th2.start();
return a.exec();
}
void MyThread::run()
{
for( int count = 0, x=0; count < 20000000; count++, x++ )
{
qDebug()<<x;
}
}
#ifndef THREAD_H
#define THREAD_H
#include <qthread.h>
#include <QThread>
class MyThread : public QThread
{
Q_OBJECT
protected:
void run();
};
#endif // THREAD_H
QT += core thread
QT -= gui
TARGET = temp
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
HEADERS += \
thread.h
а вот вывод такой:
...
406010
406011
406012
406013
406014
406015
...
а по идее должен быть типа
...
406010
406010
406011
406011
406012
406012
...
PS: как присвоить приоритет
th.start(Priority priority = HighestPriority);
Так не хочет (из хелпа)
th2.setPriority(QThread::HighestPriority);
вот так
После применения приоритетов
713245
726544
713246
726545
713247
726546
выходит один спешит? не пойму совсем
PSS: можно ли выбрать ядро для выполнения функции?
Автор: Алексей1153 4.10.2010, 18:31
Цитата(RazrFalcon @ 4.10.2010, 17:31)
а по идее должен быть типа
...
406010
406010
406011
406011
406012
406012
это слишком идеальный вывод, если ничего специально для этого не делать
Цитата(RazrFalcon @ 4.10.2010, 17:31)
713245
726544
713246
726545
713247
726546
а вот это больше похоже на правду
он не спешит, он сдвинут по фазе
Автор: RazrFalcon 4.10.2010, 19:02
Цитата(Алексей1153 @ 4.10.2010, 18:31)
это слишком идеальный вывод, если ничего специально для этого не делать
Ну мне 100% синхронность не нужна, так что нормально.
Цитата(Алексей1153 @ 4.10.2010, 18:31)
он не спешит, он сдвинут по фазе
?!
Я так понимаю что они не одинаково идут из-за того что в системе еще куча остальных процессов запущенно.
Но я так и не пойму почему не 100% оба ядра, оно(суммирование в цикле) что, мало хавает просто?
Мне интересно что надо сделать чтоб полностью забить ядра, бесконечный цикл?!
И последнее, тот пример выше, он правильный?! Это настоящая многопоточность, не семафор?
Автор: Алексей1153 4.10.2010, 19:32
в среднем где-то на 75% загружен процессор у тебя получается
а притормаживает его, наверное, qDebug()<<x;
Хотя, фиг знает
Цитата(RazrFalcon @ 4.10.2010, 22:02)
Это настоящая многопоточность, не семафор?
это точно многопоточность, так как у тебя больше одного потока. Их у тебя аж 3 ))
при чём тут семафор ? Семафор вроде предназначен для ограничения одновременного доступа потоков-читателей ресурса
Цитата(RazrFalcon @ 4.10.2010, 22:02)
И последнее, тот пример выше, он правильный?!
а это зависит от поставленной задачи
Автор: RazrFalcon 4.10.2010, 20:06
Цитата(Алексей1153 @ 4.10.2010, 19:32)
а притормаживает его, наверное, qDebug()<<x;
так я загрузить по максимуму и пытаюсь
Цитата(Алексей1153 @ 4.10.2010, 19:32)
это точно многопоточность, так как у тебя больше одного потока. Их у тебя аж 3 ))
при чём тут семафор ? Семафор вроде предназначен для ограничения одновременного доступа потоков-читателей ресурса
Почему 3-и? С семафорами я что то попутал, я имел ввиду что есть такие варианты, что просто поток кидается то на одно ядро, то на другое, и выглядит как загрузка обеих ядер, а на самом деле та же однопоточность
Цитата(Алексей1153 @ 4.10.2010, 19:32)
а это зависит от поставленной задачи
Задача пока разобраться просто с многопоточностью и все, работают 2-а потока, ну и хорошо, меня это устраивает.
Автор: Алексей1153 4.10.2010, 20:11
Цитата(RazrFalcon @ 4.10.2010, 23:06)
Почему 3-и?
ну как же - один основной и два дочерних.
Цитата(RazrFalcon @ 4.10.2010, 23:06)
я имел ввиду что есть такие варианты, что просто поток кидается то на одно ядро, то на другое, и выглядит как загрузка обеих ядер, а на самом деле та же однопоточность
хм, вроде бы нельзя так сделать, чтоб один поток выполнялся на двух ядрах. Хотя, может быть, я чего-то не знаю ))
Автор: RazrFalcon 4.10.2010, 20:14
Цитата(Алексей1153 @ 4.10.2010, 20:11)
ну как же - один основной и два дочерних.
Непонятно?! То есть сама прога, и еще 2-а моих?! То есть можно один цикл в main'е запустить а второй в потоке втором ?!
Цитата(Алексей1153 @ 4.10.2010, 20:11)
хм, вроде бы нельзя так сделать, чтоб один поток выполнялся на двух ядрах. Хотя, может быть, я чего-то не знаю ))
Я имел ввиду не одновременно, а поочередно, где то, когда то находил что то такое. Чуть-чуть на одном ядре, потом на втором, и снова на первом. Короче может это меня глючит.
Автор: Алексей1153 4.10.2010, 20:43
Цитата(RazrFalcon @ 4.10.2010, 23:14)
Непонятно?! То есть сама прога, и еще 2-а моих?! То есть можно один цикл в main'е запустить а второй в потоке втором ?!
процесс всегда состоит хотя бы из одного потока. Если явно не запускать дочерние потоки и не использовать компоненты/классы, которые это делают, то приложение будет работать в одном потоке
Да, можешь сделать один цикл в main (основной поток), другой в дочернем потоке. Будет два цикла в разных потоках. Только учитывай, что основной поток, попав в бесконечный цикл, перестанет реагировать на события клавиатуры и мыши, а также на на события от ОС ))
Автор: RazrFalcon 4.10.2010, 21:05
Ну в общем понятно. Ну я так понимаю желательно конечно 2-а потока создавать. Все равно в этот момент "главный" поток в простое.
Как вообще привязать потоки к ядрам. Чтоб они не перескакивали. То есть, это делать на первом ядре, а это на втором и не как по другому.
Автор: ufna 5.10.2010, 9:19
думаю средствами Qt этого не сделать, нужно копать в сторону системных API и т.п.
Т.к. это пока извечная проблема, что большинство программ на работу с несколькими ядрами не рассчитаны, система сама решает что куда положить.
Кстати, qDebug() в большей степени будет нагружать не оба потока, т.к. вывод идет в одну консоль - ее он грузить и будет. К примеру, если qDebug() отображать будет некуда, программа будет работать куда быстрее. Потому если хочешь создать нагрузку, лучше сделать что-нибудь другое.
Автор: RazrFalcon 5.10.2010, 18:21
Еще парочку моментов.
1) Когда я создаю 2-а потока, то на самом деле их 3-и.
2) Я не выбираю ядра, то есть сама система выбирает. Она может их (потоки) поменять местами во время работы?
3) Когда прога работает основным потоком, а потом я создаю 2-й поток, то он помещается на свободное ядро (1-е, 2-е, 3-е и тд).
4) Как я понял с гуем и файлами лучше работать в один поток.
Автор: CodeHunter 5.10.2010, 18:49
Цитата(RazrFalcon @ 5.10.2010, 18:21)
Она может их (потоки) поменять местами во время работы?
Нет !! Это передача инфы между ядрами(процесорами) очень затратное время !!
Автор: Sokoloff 5.10.2010, 20:02
Цитата(RazrFalcon @ 5.10.2010, 19:21)
Еще парочку моментов.
1) Когда я создаю 2-а потока, то на самом деле их 3-и.
2) Я не выбираю ядра, то есть сама система выбирает. Она может их (потоки) поменять местами во время работы?
3) Когда прога работает основным потоком, а потом я создаю 2-й поток, то он помещается на свободное ядро (1-е, 2-е, 3-е и тд).
4) Как я понял с гуем и файлами лучше работать в один поток.
1) Да ты создаешь не 2-а потока а 2-а
дополнительных потока. Ведь main тоже должен выполняться в потоке, поэтому у любой программы сразу есть один поток, это "основной поток". В нем отрисовываются/обновляются контролы. Замечал наверное, иногда окна программ становятся белыми, и программы не отвечают на нажатия кнопок и мыши, это когда основной поток чем то сильно занят и не успевает обработать GUI.
2) Ядра ты не выбираешь, система сама лучше знает как разместить задачи. Ведь в системе кроме твоей программы еще куча всего крутиться, и другие программы то-же хотят поработать, так что это задача системы оптимально раскидать задачи по ядрам.
3) Скорее всего да. Хотя на 100% гарантировать нельзя, смотри п.2 про чужие программы.
4) С гуем лучше работать не просто в один поток а в основном потоке. А что значит с файлами? Простая ситуация если одновременно надо обрабатывать несколько файлов - можно каждый файл обрабатывать в отдельном потоке. Но надо помнить о синхронизации между потоками. Гораздо более сложная ситуация если надо обрабатывать один большой файл, если работу можно разбить на одновременные подзадачи, то можно обрабатывать части файла в несколько потоков. Но это гораздо сложнее с точки зрения синхронизации. В общем делать потоки, или нет, и сколько зависит от задачи.
P.S. Какие у тебя разнообразные интересы и GUI/CLI, и библиотеки, и время выполнения, и потоки. Ты просто изучаешь разные вещи или что-то реальное пишешь, во втором случае IMHO что-то ты с дизайном программы мудришь, возможно твою задачу можно решить проще. Опиши задачу, тебе подскажут куда копать.
Автор: RazrFalcon 5.10.2010, 22:34
Цитата(Sokoloff @ 5.10.2010, 20:02)
А что значит с файлами?
Да я про обычный текстовик думал. Ну а в принципе все как я и думал.
Цитата(Sokoloff @ 5.10.2010, 20:02)
P.S. Какие у тебя разнообразные интересы и GUI/CLI, и библиотеки, и время выполнения, и потоки. Ты просто изучаешь разные вещи или что-то реальное пишешь, во втором случае IMHO что-то ты с дизайном программы мудришь, возможно твою задачу можно решить проще. Опиши задачу, тебе подскажут куда копать.
В общем я мучать начал openCV. А потом пошло. Интерфейс не нужен в общем - значит надо с консолькой разобраться, ну или лубу написать а потом подключать к гую. Потом понял что виснет безбожно - распараллеливание. Потом надо понять на сколько мои усилия сделали ее более быстрой - вот и время понадобилось. А в общем я просто решил поучится разному. Дизайнер из меня никудышный, вот и мучаю всякое. Начал OGRE и bullet physics учить, понял что многого не знаю, а они без оптимизации вообще деревянные и на моем ноуте не первой свежести вообще еле идут. Вот и решил основам оптимизации поучится. Помочь мне нечем, просто сталкиваюсь с проблемой и пытаюсь решить походу.
Автор: Sokoloff 5.10.2010, 23:26
Цитата(RazrFalcon @ 5.10.2010, 23:34)
Цитата(Sokoloff @ 5.10.2010, 20:02)
А что значит с файлами?
Да я про обычный текстовик думал. Ну а в принципе все как я и думал.
Если обычный текстовик и размер не большой, то не парься читай в основном потоке, никто задержки не заметит.
Про OpenCV подсказать не смогу, не сталкивался. Про GUI/CLI ответил в http://www.forum.crossplatform.ru/index.php?s=&showtopic=5652&view=findpost&p=40804.
Автор: Iron Bug 6.10.2010, 10:53
по первому посту:
если юзаешь вывод куда-то - это сильно тормозит исполнение. любой вывод - чудовищно медленный.
забить проц наглухо можно любым бесконечным циклом. и добавить атомарное выполнение или риал-тайм приоритет - тогда точно кердык: вырубать комп отключением питания, ибо клавиатура и всё остальное станут бесполезны только нафига это, если не секрет?
а из двух потоков писать в один файл лучше так: создать общее хранилище для сообщений и туда их оперативно сбрасывать из рабочих потоков (естественно, под мьютексами), а из основного потока (ну или из какого-то третьего) периодически сбрасывать накопленное в хранилище в файл.
Автор: RazrFalcon 11.10.2010, 21:01
И снова непонятно что
#include <QtCore/QCoreApplication>
#include <QString>
#include <QDebug>
#include <qthread.h>
#include <QThread>
class MyThread : public QThread
{
Q_OBJECT
protected:
void run();
};
class MyThread2 : public QThread
{
Q_OBJECT
protected:
void run2();
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyThread th;
MyThread th2;
th2.setPriority(QThread::HighestPriority);
th.setPriority(QThread::HighestPriority);
th.start();
th2.start();
for( int count = 0, x=0; count < 20000000; count++, x++ ) qDebug()<<x<<"+one";
return a.exec();
}
void MyThread::run()
{
for( int count = 0, x=0; count < 20000000; count++, x++ ) qDebug()<<x<<"+two";
}
void MyThread2::run2()
{
for( int count = 0, x=0; count < 20000000; count++, x++ ) qDebug()<<x<<"+three";
}
В выводе вообще "+three" нет, и +one | +two как то по странному выводятся, то долго один, потом долго другой, то по очереди (короткое время совсем).
Я так понимаю это по тому что основной процесс (one) у меня без приоритета запускается.
Суть в том что я не пойму как запустить два Разных процесса, одинаковые работают, а вот с разными не получается.
-----------------------------------------
Еще один не совсем логичный случай
class MyThread : public QThread
{
public:
void run(int i);
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyThread th, th2;
th.start();
th.run(1);
th2.run(2);
return 0;
return a.exec();
}
void MyThread::run(int z)
{
if (z==1) for( int count = 0, x=0; count < 10; count++, x++ ) qDebug()<<x<<"+one";
if (z==2) for( int count = 0, x=0; count < 10; count++, x++ ) qDebug()<<x<<"+two";
}
0 +one
1 +one
2 +one
3 +one
4 +one
5 +one
6 +one
7 +one
8 +one
9 +one
0 +two
1 +two
2 +two
3 +two
4 +two
5 +two
6 +two
7 +two
8 +two
9 +two
QThread: Destroyed while thread is still running
Они же должны выполнятся параллельно а не последовательно.
Автор: Алексей1153 12.10.2010, 6:18
RazrFalcon, ОС раздаёт всем потокам всех процессов кусочки времени (time slices), в винде, к примеру, это около 16 мс (если не вру). Так обеспечивается многозадачность ОС
Поток волен в это время вовсю работать (если только его ядро системы не прерывает для каких-то нужд). Они у тебя и работают - видимо, за этот слайс поток успевает вывести столько сообщений.
Мне только осталось неясно, почему лог так быстро закончился
А вот ежели отдавать часть слайса в систему методом msleep(0) , тогда всё будет вперемешку, по идее
void MyThread2::run2()
{
for( int count = 0, x=0; count < 20000000; count++, x++ )
{
qDebug()<<x<<"+three";
msleep(0);//поток отдаёт остаток своего времени для работы другим потокам
}
}
Автор: Iron Bug 12.10.2010, 6:49
Цитата(RazrFalcon @ 12.10.2010, 0:01)
В выводе вообще "+three" нет
правильно. и не будет, потому что:
MyThread th;
MyThread th2;
они оба выдают "+two". внимательнее надо писать код
Автор: Алексей1153 12.10.2010, 7:03
гы, а я и не обратил внимания ))
Автор: RazrFalcon 12.10.2010, 14:38
Цитата(Алексей1153 @ 12.10.2010, 6:18)
Мне только осталось неясно, почему лог так быстро закончился
Лог от последнего примера, там до 10 как раз и есть.
Цитата(Алексей1153 @ 12.10.2010, 6:18)
они оба выдают "+two". внимательнее надо писать код
Да уш, закрутился называется.
Но суть в том что я не пойму как заставить разные функции выполнятся.
Сейчас я создаю 2-а (3-и с основным) потока, которые делают одно и тоже.
А мне надо чтоб один поток делал одно, а второй другое. Хотя в принципе можно также чтоб одно и тоже действие но с разными параметрами.
И вопрос в том: если я создаю еще 2-а исполняющих потока - то основной (main) в простое просто. И как можно дать приоритет main'у. Я то только новым задаю приоритет потокам. К слову, он вообще сильно влияет. Я пока что особой разницы не заметел, хотя у мне я то и функция не ахти =).
Что б было понятно что за ересь я написал выше, такой вот пример:
Есть захват видео с камеры, грубо говоря покадрово. То есть я беру 1-й кадр - его в потока пусть обрабатывается, и пока он обрабатывается беру следующий, и его во второй поток. Потом первый обработался - вывели на экран, и первый берет уже 3-й кадр ну и тд. Главное чтоб они выводились во время а не как попало (1,2,3,4,5... а не 1,3,2,5,4 к примеру). Ну и соответственно сколько ядер, столько и обрабатывается кадров одновременно, это на будущие конечно.
Автор: Iron Bug 12.10.2010, 15:11
Цитата(RazrFalcon @ 12.10.2010, 17:38)
Главное чтоб они выводились во время а не как попало (1,2,3,4,5... а не 1,3,2,5,4 к примеру)
присваиваешь потокам "номера" и гоняешь циклический счётчик. каждый раз ждёшь ответа о готовности обработки кадра от потока с номером по счётчику и увеличиваешь счётчик (циклически). иначе ты не добьёшься синхронизации просто никак. процессоры могут быть нагружены другими задачами, система может использовать их для обработки прерываний и т.п., поэтому никогда нельзя гарантировать скорость обработки, даже при высоком приоритете.
в обычной (не embedded) венде высокий приоритет процесса вообще ничего не значит, практически. при активной работе сетевой карты задержки обработки "риал-тайм" прерываний от чего угодно могут доходить до 200 мс, как два пальца об асфальт. и это на уровне драйвера! а софт вообще курит бамбук и на настоящий риалтайм надеяться никак не может.
Автор: RazrFalcon 12.10.2010, 15:29
Так все и выясняется. Ну в общем ясно. Буду пробовать.
_________________________________________________
class MyThread : public QThread
{
public:
void run(int i);
};
class MyThread2 : public QThread
{
public:
void run2(int i);
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyThread th;
MyThread2 th2;
//th.setPriority(QThread::HighestPriority);
th.start();
//th.run(1);
//th2.run2(2);
th2.start();
return 0;
return a.exec();
}
void MyThread::run(int z)
{
if (z==1) for( int count = 0, x=0; count < 1000000; count++, x++ ) qDebug()<<x<<"+one";
if (z==2) for( int count = 0, x=0; count < 1000000; count++, x++ ) qDebug()<<x<<"+two";
}
void MyThread2::run2(int z)
{
if (z==1) for( int count = 0, x=0; count < 1000000; count++, x++ ) qDebug()<<x<<"+one";
if (z==2) for( int count = 0, x=0; count < 1000000; count++, x++ ) qDebug()<<x<<"+two";
}
И снова ерунда.
QThread: Destroyed while thread is still running
QThread: Destroyed while thread is still running
А если закомментировать start()'ы, и сделать через run(1)|run(2) то выводится 1000000 раз one, а потом столько же two =|
Автор: Алексей1153 12.10.2010, 18:56
Цитата(RazrFalcon @ 12.10.2010, 18:29)
MyThread th;
MyThread2 th2;
//th.setPriority(QThread::HighestPriority);
th.start();
//th.run(1);
//th2.run2(2);
th2.start();
return 0;
ну дык, ещё бы - создаёшь локально, они радостно запускаются, а потом ты их лопатой ))
Автор: RazrFalcon 12.10.2010, 19:20
Цитата(Алексей1153 @ 12.10.2010, 18:56)
ну дык, ещё бы - создаёшь локально, они радостно запускаются, а потом ты их лопатой ))
а?
Автор: Алексей1153 12.10.2010, 20:31
RazrFalcon, когда return 0 выкидывает из функции main, то локальные переменные выходят из области видимости и разрушаются
Автор: RazrFalcon 12.10.2010, 22:25
Алексей1153
без return 0 вообще не стартует, то есть стартует но даже вывода нет.
Автор: Iron Bug 13.10.2010, 6:53
читать и читать, как создаются и работают потоки и что такое область видимости переменных. до просветления.
Автор: RazrFalcon 14.10.2010, 20:19
Что за ерунда, прога работает только если функция исполняемая предопределена как
void MyThread::run()
если вместо run написать что то другое вообще не работает.
При условии что везде функция имеет одно и то же имя.
То есть я не ошибся при создании класса. Так как компиляци успешна, просто потом стоит на месте.
Почему?
В чем разница между .run() и .start()? У меня одинаковый результат вообще.
Почему после окончания работы функции (потока) она не завершается а так и висит. return; не помогает.
Автор: igor_bogomolov 14.10.2010, 20:38
RazrFalcon, ты бы документацию читал, там все подробно описано
Цитата(RazrFalcon)
В чем разница между .run() и .start()?
start создает доп поток и вызывает run уже в новом, созданным им потоке. Если ты просто вывозишь run доп. поток создан не буден.
Цитата(RazrFalcon @ 12.10.2010, 16:29)
class MyThread2 : public QThread { public: void run2(int i); };
Здесь функция run2 всегда будет вызываться в основном потоке. Так же как и любая другая, кроме run (вызванная через старт)
Автор: RazrFalcon 14.10.2010, 20:48
Цитата(igor_bogomolov @ 14.10.2010, 20:38)
RazrFalcon, ты бы документацию читал, там все подробно описано
http://www.doc.crossplatform.ru/qt/4.6.x/qthread.html и тд.
Читаю, если б понимал - не спрашивал бы
Цитата(igor_bogomolov @ 14.10.2010, 20:38)
Здесь функция run2 всегда будет вызываться в основном потоке.
в том то и дело, что я не пойму как создать отличную от основной функцию/поток.
Мне надо создать 2-а разных потока! Или один, но с возможностью передачи параметров.
У меня после изменения функции run все рушится постоянно.
Все. Разобрался! Сейчас дошлифую и выложу рабочий вариант, на всякий случай. Правда не пойму почему прога не завершается сама, все делает нужное, а потом просто висит.
Автор: RazrFalcon 18.10.2010, 19:28
Опять в один поток идет все!
#include <QtCore/QCoreApplication>
#include <QProcess>
#include <QtDebug>
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <opencv/cxcore.h>
#include <sys/time.h>
#include <QThread>
using namespace cv;
timeval start, stop;
const char* cascade_name ="/media/data/Additional/cv/haarcascades/haarcascade_frontalface_alt2.xml";
CvPoint pt1, pt2;
class MyThread : public QThread
{
public:
void run( IplImage* img);
};
class MyThread2 : public QThread
{
public:
void run( IplImage* img);
};
IplImage* frame;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
cvNamedWindow("Face detection", CV_WINDOW_AUTOSIZE);
int stops=0;
CvCapture* capture = cvCreateCameraCapture(0);
MyThread th;
MyThread2 th2;
while(stops!=1)
{
frame = cvQueryFrame(capture);
//th.start();
th.run(frame);
cvShowImage("Face detection", frame);
//th.exit();
cvWaitKey(15);
//th2.start();
th2.run(frame);
cvShowImage("Face detection", frame);
cvWaitKey(15);
}
cvReleaseCapture(&capture);
cvDestroyWindow("Face detection");
return a.exec();
}
void MyThread::run( IplImage* img)
{
обработка
return;
}
void MyThread2::run( IplImage* img)
{
обработка
return;
}
Автор: Алексей1153 18.10.2010, 20:07
Цитата(RazrFalcon @ 18.10.2010, 22:28)
Опять в один поток идет все!
а в чём это выражается ?
А это шо за хрень неведомая
while(stops!=1)
{
...
//th.start();
th.run(frame);
...
//th2.start();
th2.run(frame);
}
так всё правильно: потоки ты не запустил (//start) , а метод run вызываешь из одного потока (главного). Вот и один поток
Автор: RazrFalcon 18.10.2010, 20:14
В том то и проблема.
Если использовать start - то 2-а потока еще добавляю, но я не могу функции run() послать переменную.
А если через run - то все в один поток, но зато я могу передать свои значения.
Как это правильно сделать?
PS выражается в том что загружено только одно ядро.
Еще одну ошибку нашел.
Запустил дебаг, а оно пошло создавать потоки, когда было >100 я остановил прогу.
То есть их нужно закрывать еще =(
Я тут повешусь с этими потоками.
Автор: Алексей1153 18.10.2010, 20:23
RazrFalcon, пипец...
конечно же, если в цикле вызывать start, будет много потоков. И для них 100 ядер не надо, чтобы это определить )))
Параметры передай через члены классов MyThread и MyThread2
Автор: RazrFalcon 18.10.2010, 20:28
Цитата(Алексей1153 @ 18.10.2010, 20:23)
Параметры передай через члены классов MyThread и MyThread2
? Не понял. Как передать то?
То есть мне надо сами циклы в run() уже делать?
Создаю два потока, а они оба с while.
Я правильно понял.
PS извиняюсь за тупость, но я вторую неделю мучаю эти потоки, и пока просветления никакого.
Автор: Алексей1153 18.10.2010, 20:39
вот смотри, наглядно то, что ты сделал - с одним потоком:
а вот, когда действительно 3 потока
Цитата(RazrFalcon @ 18.10.2010, 23:28)
? Не понял. Как передать то?
вот так
class MyThread
{
int Превеед_я_член_класса_приятно_познакомиться;
...
};
Автор: RazrFalcon 18.10.2010, 20:47
Логика работы потоков мне ясна, я не понимаю тока реализацию саму.
Мне нужно:
взять изображение с камеры
обработать
отобразить обработанное.
В потоках только обработка. А захват и отображение main.
Как передать захвачено изображение потоку?
Это вообще логично/возможно для двух ядер?
Автор: Алексей1153 18.10.2010, 21:01
Цитата(RazrFalcon @ 18.10.2010, 23:47)
Логика работы потоков мне ясна, я не понимаю тока реализацию саму
неа, не ясна тебе работа потоков. Поток - это процедура (голая такая процедура, и НИЧЕГО БОЛЬШЕ ВООБЩЕ) - статическая или глобальная. Только запускается эта процедура системой, а не вызывается как обычно из кода одного из потоков (в последнем случае нить, проходящая через процедуру не являет собой нового потока - смотри первый рисунок)
Под WINAPI объявление потока выглядит так:
UINT thread(LPVOID param)
{
//цикл работы
//...
return 0;
}
При чём тут ядра? Где тут ядра? Забудь про ядра!
я бы так сделал:
1) первый поток - захват, помещение в очередь обработки
2) второй поток - извлечение из очереди обработки, обработка, отправка в БД/ОЗУ/файл
3) основной поток - отображение из БД/ОЗУ/файла
чтение/запись надо синхронизировать - тут наблюдается две таких точки (запись в очередь/извлечение из очереди , запись в хранилище/извлечение из хранилища)
Автор: RazrFalcon 18.10.2010, 22:11
Мне нужна многопоточность, только для ускорения работы, а такой алгоритм, как вы написали, не очень то похож на высокопроизводительный.
Вот если бы оно в два пото обрабатывало, это мне понятно, а просто раскидать по потокам
Автор: Алексей1153 19.10.2010, 6:43
RazrFalcon,
если хочешь выжать из процессора максимальную скорость, то:
- обеспечь, что запущено только твоё приложение.
- не используй дополнительных потоков.
Поток создаёт удобство в разбивании задачи на параллельные процессы, но скорости не добавляет, а убавляет.
Цитата(RazrFalcon @ 19.10.2010, 1:11)
а такой алгоритм, как вы написали, не очень то похож на высокопроизводительный
зато он проверен временем и поддаётся отладке и регулированию
Цитата(Алексей1153 @ 19.10.2010, 9:18)
- не используй дополнительных потоков.
а вот тут я немного наврал. Использование потоков имеет-таки смысл на многоядерных процессорах. Так что, может и скорость выше получится, чем с одним потоком
потока намечается 3, поэтому шустрее всего будет работать на 3+ ядерном процессоре.
Автор: RazrFalcon 19.10.2010, 8:49
Ладно, буду пробовать.
А то что, больше потоков, больше мороки, я уже вижу
Автор: Алексей1153 19.10.2010, 8:56
Цитата(RazrFalcon @ 19.10.2010, 11:49)
Ладно, буду пробовать.
ты меня пугаешь!
Что именно пробовать будешь ? ))
Автор: Iron Bug 19.10.2010, 9:28
Цитата(Алексей1153 @ 19.10.2010, 0:01)
я бы так сделал:
1) первый поток - захват, помещение в очередь обработки
2) второй поток - извлечение из очереди обработки, обработка, отправка в БД/ОЗУ/файл
3) основной поток - отображение из БД/ОЗУ/файла
чтение/запись надо синхронизировать - тут наблюдается две таких точки (запись в очередь/извлечение из очереди , запись в хранилище/извлечение из хранилища)
Цитата(RazrFalcon @ 19.10.2010, 1:11)
такой алгоритм, как вы написали, не очень то похож на высокопроизводительный
алгоритм вполне нормальный. просто пункт 2 ты можешь размножить до количества процессоров (но помни, что у тебя ещё приём и итоговое отображение где-то должны крутиться!). а что касается распараллеливания в QT - тут я не спец. наверняка можно указать номер проца. но это, опять же, через класс потока, а не потом, при его работе.
а с потоками, как видно, ничего тебе не понятно. так что читай матчасть основательно и про реализацию потоков в QT. благо, тут добрые люди вроде как даже занимаются переводом этого добра на русский язык, если вдруг по-английски непонятно.
Автор: RazrFalcon 19.10.2010, 10:53
Цитата(Алексей1153 @ 19.10.2010, 8:56)
Что именно пробовать будешь ? ))
Что значит "что"?
Пытаться разобраться с потоками, попробую разные варианты использования потоков и тд.
Цитата(Iron Bug @ 19.10.2010, 9:28)
алгоритм вполне нормальный. просто пункт 2 ты можешь размножить до количества процессоров
У меня 1-н процессор и 2-а ядра
Цитата(Iron Bug @ 19.10.2010, 9:28)
а что касается распараллеливания в QT - тут я не спец.
А чем вы пользуетесь?
Цитата(Iron Bug @ 19.10.2010, 9:28)
если вдруг по-английски непонятно.
Прекрасно понятно, толку правда пока не очень, все равно
Вы о кьютешном распараллеливании говорите или вообще?
Автор: Алексей1153 19.10.2010, 11:33
RazrFalcon, поток - это понятие ОС (и даже - процессора) .
Автор: Iron Bug 19.10.2010, 13:03
Цитата(RazrFalcon @ 19.10.2010, 13:53)
У меня 1-н процессор и 2-а ядра
для ОС количество ядер и есть количество "процессоров". ибо для неё важен вычислитель, а не внутренняя архитектура чипа.
Цитата(RazrFalcon @ 19.10.2010, 13:53)
А чем вы пользуетесь?
для меня графика не важна, в основном консольные приложения и boost, а если кое-где требуется графика, то wxWidgets. он значительно легче и может компилиться статически, что важно для переносимости с машины на машину под одной системой. у меня часто случается, что программы используются "в поле" и лучше иметь один переносимый исполняемый файл, чем поставлять кучу библиотек.
Автор: RazrFalcon 4.11.2010, 18:41
Разобрался с потоками в общем.
Но теперь другая проблема.
Сделал обработку в 2-х потоках. Все хорошо. Грузит оба ядра на ~90%.
Но если считать время обработки общее, то оно практически на 10-15% ниже чем у однопоточной версии.
Пробовал делать ввод-вывод в главном потоке, обработка во втором, вроде шустрее, но совсем незначительно, иногда даже медленней.
#include <QtCore/QCoreApplication>
#include <QtDebug>
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <opencv/cxcore.h>
#include <sys/time.h>
#include <QThread>
using namespace cv;
timeval start, stop, tstart, tstop;
const char* cascade_name ="../cv/haarcascades/haarcascade_frontalface_alt2.xml";
CvPoint pt1, pt2;
class MyThread : public QThread
{
public:
void run();
};
class MyThread2 : public QThread
{
public:
void run();
};
void detect_and_draw( IplImage* img )
{
//обработка, неизменна
}
IplImage* frame1;
IplImage* frame2;
bool flag1=false, flag2=false, flag3=false, flag4=false;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
cvNamedWindow("Face detection", CV_WINDOW_AUTOSIZE);
int stop=0;
CvCapture* capture = cvCreateCameraCapture(0);
MyThread th;
MyThread2 th2;
while(stop!=1)
{
if (flag3==false)
{
frame1 = cvQueryFrame(capture);
th.start();
cvWaitKey(5);
flag3=true;
}
if (flag4==false)
{
frame2 = cvQueryFrame(capture);
th2.start();
flag4=true;
}
if (flag1==true) {cvShowImage("Face detection", frame1); flag1=false; flag3=false;}
if (flag2==true) {cvShowImage("Face detection", frame2); flag2=false; flag4=false;}
}
cvReleaseCapture(&capture);
cvDestroyWindow("Face detection");
return a.exec();
}
void MyThread::run()
{
detect_and_draw(frame1);
flag1=true;
}
void MyThread2::run()
{
detect_and_draw(frame2);
flag2=true;
}
Код сырой конечно, но тут скорее ошибка в фундаментальных основах. Иначе чем объяснить то что в двух потоках виснет намного хуже чем в одном.
Автор: Iron Bug 4.11.2010, 18:57
а зачем ты в цикле создаёшь и убиваешь стопицот потоков?
понятно, что на создание потока и контекста требуется дофига процессорного времени. или QThread::start не создаёт контекст?
не проще ли в рабочих потоках сделать циклическую обработку данных из какого-то буфера (только аккуратно, с защитой данных между потоками)? по-хорошему, там при этом ещё нужно бы прикрутить какие-то события, что буфер непуст - чтобы потоки спали, когда не требуется выполнять никаких действий.
и, кстати, не забывай про многопотчность! дожидается ли QThread::start завершения потока? я не спец в QT, но есть подозрение, что нет. а если нет, то в случае, когда у тебя основной цикл будет читать кадры быстрее, чем рабочие потоки смогут их обрабатывать, то у тебя просто затрётся рабочий указатель на данные и ты получишь ошибку рантайма или просто кривое изображение.
а в случае, если QThread::start дожидается окончания потока - то у тебя нет никакой параллельности вообще.
Автор: RazrFalcon 4.11.2010, 19:16
Создаю каждый раз поток, так как, если через дебаг смотреть, то после окончания обработки поток убивается, вот и приходится заново его создавать. Ну а без дебага, просто пустое окно.
На счет циклической обработки: имеется ввиду вайлы в потоки впихнуть? Пробовал, ошибки были, не помню уже какие.
А насчет того что кадров берется больше чем я успеваю обработать, я знаю, но пока с потоками не разберусь, не буду трогать, я просто пока ставлю больше время до захвата следующего кадра.
Автор: Iron Bug 4.11.2010, 19:26
у меня такое ощущение, что ты совершенно не понимаешь сути параллельной обработки данных.
не поленись, сядь и нарисуй картинку: как всё должно работать, схематически изобрази связи и вызовы и что за чем идёт, стрелками. и потом составь алгоритм обработки, подробно, на бумажке. и только после этого садись писать код. а то ты городишь непонятно что и понятно, что оно не работает. потому что там принципиальные ошибки, даже не программистские, а чисто алгоритмические.
Автор: RazrFalcon 4.11.2010, 19:31
Сейчас нарисую
Я и не отрицаю свои ошибки. Я даже точно знаю что они есть.
Проблема что сложно разобраться, вот и мучаюсь. Понемногу.
уже уверен что неправильно
Автор: PAFOS 30.12.2010, 15:52
Вклинюсь в дискуссию)
В свое время много-много убил времени на понимание потоков и как Qt с ними обращается))
Для достижения максимальной производительности необходимо создавать столько потоков, сколько физически одновременно может обработать проц.
Для двухядерников идеальным будет два потока, для четырех - четыре.
Еще момент, на создание самого потока у системы уходит уйма времени, поэтому не стоит убивать поток сразу после того как он обработал кадр.
После обработки кадра, поток должен ждать , когда ему сунут новый кадр для обработки.
При таком ожидании лучше всего использовать условные переменные. Условные переменные - разновидность объекта для синхронизации потоков.
Вот код, отображающий все вышеперечисленные моменты)
в коде я предполагаю, что есть класс Frame, который инкапсулирует такую сущность как кадр с камеры.
класс Frame имеет член - int number, который указывает его порядковый номер )
// Класс, который будет обрабатывать кадр в отдельном потоке
class Thread : public QThread
{
private:
void run();
public:
Frame mFrame; // Кадр, который будет обрабатывать поток
// после обрабтки кадра, переменная mFrame должна содержать измененный кадр
QWainCondition mCondition;
signals:
// Сигнал испускается потоком, когда тот завершит обработку кадра
void processingFinished();
}
void Thread::run()
{
QMutex mutex;
for(;;)
{
// Здесть мы ожидаем, когда контролирующий поток даст "добро" на обработку кадра
// предполагается, что перед тем как потоку дадут "добро", переменная mFrame будет содержать кадр, который необходимо обработать
mutex.lock();
mCondition.wait(&mutex);
// Код обработки помещаем тут
// Обработку завершили, высылаем сигнал
emit processingFiniched();
mutex.unlock();
}
return;
}
// Класс. который распределяет кадры между потоками
class Constructor : public QObject
{
Q_OBJECT
public:
// Массив обработанных кадров, в правильном порядке
QList<Frame> mFrames;
public slots:
// Слот, который будет вызываться при завершении одним из потоков обработки кадра
void on_processingFinished( );
}
// Этот слот будет выполняться в основном потоке программы
void Constructor::on_processingFinished( )
{
// Так мы определяем какой экземпляр класса завершил обработку
Thread *t = dynamic_cast<Thread*>( sender() );
// Получаем обработанный кадр
Frame frm = t->mFrame;
// Записываем его в массив, в нужное место
mFrames[ frm.number() ] = frm;
// Задаем потоку кадр, который он должен обработать
t->mFrame = get_next_frame();
// Даем "добро" на обработку кадра
t->mCondition.wakeOne();
}
int main( int argc, char **argv )
{
QCoreApplication a(argc,argv);
Constructor c;
// Резервируем место в массиве под все кадры
c.mFrames.reserve( frames_count );
// Так определяем кол-во потоков, которое РЕАЛЬНО ПАРАЛЛЕЛЬНО могут выполняться в системе
int ideal_threads = QThread::idealThreadCount();
// Создаем и запускаем потоки
for( int i = 0; i < ideal_threads; i++ )
{
Thread *t = new Thread;
// Соединяем сигнал потока о завершении обработки со слотом рапределителя кадром
connect( t, SIGNAL(processingFinished()), &c, SLOT(on_processingFinished() );
// Запускаем поток
t->start();
// Задаем кадр, который необходимо обработать потоку
t->mFrame = get_next_frame();
// Даем добро на обработку кадра
t->mCondition.wakeOne();
}
return a.exec();
}
Вероятно многое может показаться непонятным, но я постараюсь ответить на них )
Автор: RazrFalcon 11.1.2011, 22:57
Большое спасибо. Очень понятный код. Буду разбираться.
У вас опечатка:
QWaitCondition
processingFinished
Еще бы инклуды написали, было бы вообще супер =)
Автор: PAFOS 12.1.2011, 18:38
Цитата(RazrFalcon @ 11.1.2011, 22:57)
Большое спасибо. Очень понятный код. Буду разбираться.
У вас опечатка:
QWaitCondition
processingFinished
Еще бы инклуды написали, было бы вообще супер =)
Извиняюсь за опечатки, я писал за 20 минут до завершения последнего рабочего дня ушедшего года))
Этот код лишь как пример, не стоит слепо следовать ему )
Автор: RazrFalcon 24.1.2011, 23:22
Что мои шаги в многопоточности оооочень медленные.
Может кто нибудь написать мааааленький пример?! В котором будет открываться 10 изображений и поворачиватбся (по 5-ть в потоке), а потом по очереди выводится на форме.
Коментарии к коду выше: Constructor c; - что это?
Автор: igor_bogomolov 24.1.2011, 23:33
Цитата(RazrFalcon @ 24.1.2011, 23:22)
Коментарии к коду выше: Constructor c; - что это?
Мда. Всё гораздо хуже чем я думал
Забудь про многопоточность, забудь про сетевые взаимодействия, забудь вообще про Qt. Для начала подтяни базовые знания с++
Автор: RazrFalcon 24.1.2011, 23:58
ЭЭ... Возможно.
Но мне бы пример...
Автор: Iron Bug 25.1.2011, 9:17
Цитата(RazrFalcon @ 25.1.2011, 1:22)
Может кто нибудь написать мааааленький пример?! В котором будет открываться 10 изображений и поворачиватбся (по 5-ть в потоке), а потом по очереди выводится на форме.
это уже не "мааааленький пример", а вполне себе функциональная утилитка. ты выбери: либо ты хочет стать программистом и тебе нужно много и долго учиться, либо ты работаешь где угодно, платишь деньги и тебе пишут софт другие люди, которым не лень изучать языки и системы.
Автор: RazrFalcon 25.1.2011, 19:21
Мне 19 лет
И я совершенно точно нигде не работаю.
А теме уже 3-и месяца, и все это время я пытаюсь с потоками разобраться.
Фактически, сейчас у меня проблема только в том что я не понимаю как не дать главному потоку убивать второстепенные до окончания их работы.
Вот если второй поток работает меньше главного (aka main) то все работает отлично.
Вот и все проблема. А пример нежен для наглядности. В мои планы входит изучение языка, в не воровство чужой интеллектуальной собственности.
Автор: igor_bogomolov 25.1.2011, 19:40
RazrFalcon, и мы сейчас отказываемся помогать не из-за вредности, поверь. Наоборот, скорее что бы направить в нужном направлении. Ты же сам написал
Цитата(RazrFalcon @ 25.1.2011, 19:21)
В мои планы входит изучение языка
Вот на это сейчас и нужно сделать основной акцент. Повторюсь, не нужно сейчас смотреть на Qt. Освой для начала основные концепции с++. У нас есть для этого специальный раздел, подможем если что
Автор: PAFOS 26.1.2011, 9:42
Цитата
Фактически, сейчас у меня проблема только в том что я не понимаю как не дать главному потоку убивать второстепенные до окончания их работы.
Если убить главный поток, то работа приложения завершится и все потоки тоже.
Это правило и исключений из него нету.
Цитата
Мне 19 лет
И я совершенно точно нигде не работаю.
Мне 20 лет
И я уже женат и работаю.))
Догоняй
Автор: RazrFalcon 26.1.2011, 20:49
Цитата(PAFOS @ 26.1.2011, 8:42)
Если убить главный поток, то работа приложения завершится и все потоки тоже.
Я его не убиваю, он сам завершается.
Цитата(PAFOS @ 26.1.2011, 8:42)
Мне 20 лет
И я уже женат и работаю.))
Догоняй
Пытаюсь
Автор: igor_bogomolov 26.1.2011, 21:29
Цитата(RazrFalcon @ 26.1.2011, 20:49)
Я его не убиваю, он сам завершается.
Ну так посмотри примеры, почитай документацию, например функции QThread::wait, посмотри как она используется
Автор: Алексей1153 27.1.2011, 20:45
Цитата(RazrFalcon @ 25.1.2011, 21:21)
как не дать главному потоку убивать второстепенные до окончания их работы
синхронизироваться же
основной поток перед завершением должен сообщить дочерним о своём намерении. Затем ждать, когда они просигналят, что можно спокойно закрывать приложение. Там хоть трава не расти - убивай и всё
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)