Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на 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;
     }
}
.h
#ifndef THREAD_H
#define THREAD_H

#include <qthread.h>
#include <QThread>

class MyThread : public QThread
{
     Q_OBJECT

protected:
     void run();
};



#endif // THREAD_H
.pro
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) *
он не спешит, он сдвинут по фазе
?! :blink:

Я так понимаю что они не одинаково идут из-за того что в системе еще куча остальных процессов запущенно.
Но я так и не пойму почему не 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

И снова непонятно что

cpp
#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) у меня без приоритета запускается.
Суть в том что я не пойму как запустить два Разных процесса, одинаковые работают, а вот с разными не получается.
-----------------------------------------
Еще один не совсем логичный случай
cpp
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";
}
log
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". внимательнее надо писать код

Да уш, закрутился называется. :rolleyes:
Но суть в том что я не пойму как заставить разные функции выполнятся.
Сейчас я создаю 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

Так все и выясняется. Ну в общем ясно. Буду пробовать.
_________________________________________________

cpp
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

:huh: читать и читать, как создаются и работают потоки и что такое область видимости переменных. до просветления.

Автор: 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 и тд.
Читаю, если б понимал - не спрашивал бы :unsure:
Цитата(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 выражается в том что загружено только одно ядро. :huh:

Еще одну ошибку нашел.
Запустил дебаг, а оно пошло создавать потоки, когда было >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

:lol:
Логика работы потоков мне ясна, я не понимаю тока реализацию саму.
Мне нужно:
взять изображение с камеры
обработать
отобразить обработанное.
В потоках только обработка. А захват и отображение 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

Мне нужна многопоточность, только для ускорения работы, а такой алгоритм, как вы написали, не очень то похож на высокопроизводительный.
Вот если бы оно в два пото обрабатывало, это мне понятно, а просто раскидать по потокам :huh:

Автор: Алексей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-а ядра :blink:

Цитата(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

Сейчас нарисую :lol:
Я и не отрицаю свои ошибки. Я даже точно знаю что они есть.
Проблема что сложно разобраться, вот и мучаюсь. Понемногу.

уже уверен что неправильно
http://itmages.ru/

Автор: 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; - что это?
Мда. Всё гораздо хуже чем я думал :unsure:
Забудь про многопоточность, забудь про сетевые взаимодействия, забудь вообще про Qt. Для начала подтяни базовые знания с++

Автор: RazrFalcon 24.1.2011, 23:58

ЭЭ... Возможно.
Но мне бы пример... :mellow:

Автор: 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)