LINUX.ORG.RU

Qt4 и балансирование QThread

 ,


0

1

Пишу на Qt и заметил такую проблему - когда система не нагружена, то два потока, делающие одно и то же (только над разными данными) завершают свою работу как раз по очереди, как это и ожидается.

Но есть серьезная проблема - когда система нагружена, то поток, который начал работать позже, может завершиться раньше первого, в итоге данные другого потока уже оказываются неактуальными.

Есть ли в Qt или на уровне системы Linux возможность делать так, чтобы задействовать два ядра и более для работы алгоритма? Чтобы поток с более новыми данными не вылезал вперед потока со старыми.

Уверен, проблема стара как мир, но я вот до такого только сейчас «дорос» :)

Организовать все это с помощью мьютексов не пробовали?

trex6 ★★★★★
()

Скорее всего, нужно подняться на уровень выше — пользоваться не QThread, а QFuture или чем-то подобным из QtConcurrent. И проблема решится сама собой.

vzzo ★★★
()
Ответ на: комментарий от vzzo

Виноват - я неправильно написал, я именно QtConcurrent+QFuture+QFutureWatcher и использую, только при нагрузке системы вылезает этот эффект.

Проблема сама по себе не решается, обработка длительная - декодирование кадра JPEG, но разрешение настолько высокое, что одного ядра не хватает, а с двумя под фоновой нагрузкой приходится отбрасывать кадры так как некоторые НОВЫЕ кадры успели обработаться раньше старых.

I-Love-Microsoft ★★★★★
() автор топика

Qt4 и балансирование QThread

это не балансирование (кстати, балансировка) QThread, это называется - допрежь как хвататься за ЯП и фреймворки произведи декомпозицию задачи в терминах многопоточного окружения

Чтобы поток с более новыми данными не вылезал вперед потока со старыми.

а кадры зависимы или независимы? если независимы - просто промаркируй их и потом собирай согласно номеркам

если зависимы или нет возможности устроить маркировку - делай «конвейер»

shty ★★★★★
()
Ответ на: комментарий от shty

кадры идут один за другим, соответственно они строго зависимы

проблема: иногда кадры декодируются вне очереди - что делать?

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

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

кадры идут один за другим, соответственно они строго зависимы

не, ты путаешь очерёдность и зависимость, зависимость - это, например, если ты выкидываешь кадр №100500 и кадр №100501 приходится выбрасывать вслед за ним, если же появление 100501 кадра никак не зависит от факты появления/не появления 100500 кадра, то они независимы

проблема: иногда кадры декодируются вне очереди - что делать?

буфер делать, и накапливать их там

номерами я уже их снабдил

и в чём проблема?

shty ★★★★★
()

На лицо неправильное понимание сущности тредов (покрайне мере тех, которые в Qt) Тебе никто не при каких условиях не гарантирует, что они будут завершаться в каком то определенном порядке! Так что упорядочивай результат их работы ручками, как тебе уже советовали.

ЗЫ: Еще один MJPEG велосипедишь?

AF ★★★
()

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

Chaser_Andrey ★★★★★
()
Ответ на: комментарий от AF

Да, именно MJPEG, но увы там кажется не сильно стандартный. Так что пока просто JPEG картинки. Пока так...

Потоки я понимаю правильно, я знаю что никто не гарантирует и _решил_ проблему нумерацией кадров, поэтому интересуюсь может есть какой-то стандартный механизм использования двух ядер, но чтобы процесс декодирования нового кадра не получал больший приоритет.

Неужели надо вручную управлять приоритетами потоков? Я готов. Если мне кто-то подтвердит что это правильное решение и они тоже так делают, я точно так же последую их опыту :)

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Изменение приоритетов только уменьшит вероятность такой ситуации. Выхода у тебя четыре: показывать все кадры по порядку, организовав очередь, либо отбрасывать более старые кадры, либо отказаться от многопоточности, либо рендерить многопоточно отдельный кадр (думаю, это вполне возможно, если покопаться в libjpeg, но зависит от формата этого джпега).

unC0Rr ★★★★★
()
Ответ на: комментарий от unC0Rr

думаю, это вполне возможно, если покопаться в libjpeg, но зависит от формата этого джпега

я вот тоже думаю в эту сторону, ведь самым реальным выходом было бы бросить все силы двух и более ядер на декодирование одного кадра, потому что разные потоки с разными кадрами только уменьшают вероятность ситуации

спасибо за мысль, пошел гуглить :)

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Да, именно MJPEG, но увы там кажется не сильно стандартный.

Настолько нестандартный, что и ffmpeg не понимает?

я знаю что никто не гарантирует и _решил_ проблему нумерацией кадров,

Пока не решил )

Неужели надо вручную управлять приоритетами потоков?

Раз ты используешь QtConcurent, то потоков у тебя не 2, а N

QFuture<T> QtConcurrent::run ( Function function, ... )
Runs function in a separate thread. The thread is taken from the global QThreadPool. Note that the function may not run immediately; the function will only be run when a thread is available.

Предстваь что у тебя есть N потоков для декодирования, и 1 поток для воспроизведения. Между этими потоками есть некий буффер, который выполняет 2 роли:

1) в буффере упорядочиваются декодированные кадры

2) буффер всегда содержит данные для потока воспроизведениея с запасом, что позволяет воспроизведению никогда не ждать декодера, если то запаздывает.

Ну и переходи от номера кадра к TimeStamp. Иначе FPS будет плавающий.

AF ★★★
()
Ответ на: комментарий от AF

я вот еще что нашел - http://libjpeg-turbo.virtualgl.org/

libjpeg-turbo is a derivative of libjpeg that uses SIMD instructions (MMX, SSE2, NEON) to accelerate baseline JPEG compression and decompression on x86, x86-64, and ARM systems. On such systems, libjpeg-turbo is generally 2-4x as fast as the unmodified version of libjpeg, all else being equal.

а я-то думал что обычный libjpeg уже оптимизирован по самые помидоры, а он лишь так... лишь бы картинку декодировало и всё

ушел тестировать libjpeg turbo, возможно мне даже и не потребуется второй поток :) на целевой платформе у меня Core 2 Duo, так что думаю на нем будет возможен сценарий 3-4x

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от unC0Rr

Поискал репозитории Федоры не-турбо версию libjpeg и не нашёл.. На чём вы все сидите??

anonymous
()
Ответ на: комментарий от unC0Rr

отвечая анонимусу, скажу что в репах её нет, но есть исходники и пакеты deb rpm на сайте sourceforge

я скачал deb и заюзал turbojpeg API, получил 150 fps 1024x768 на одном ядре amd phenom 2 - вот это гипер быстро для жыпега )))

I-Love-Microsoft ★★★★★
() автор топика
Ответ на: комментарий от AF

Вот код, на всякий случай выложу:

#include <turbojpeg.h>

bool tjpegt::benchmark_turbojpeg()
{
	QTime bench_timer;
	QFile jpeg_file;
	jpeg_file.setFileName("test.jpg");
	if(!jpeg_file.open(QIODevice::ReadOnly)) return false;
	QByteArray jpeg_data = jpeg_file.readAll();
	jpeg_file.close();

	tjhandle jpeg = tjInitDecompress();
	int jpeg_width, jpeg_height, jpeg_jpegsubsamp;
	tjDecompressHeader2(jpeg, (unsigned char*)jpeg_data.data(), jpeg_data.size(), &jpeg_width, &jpeg_height, &jpeg_jpegsubsamp);
	qDebug() << "jpeg width=" << jpeg_width << "height=" << jpeg_height << "OK";

	int image_size = jpeg_width*jpeg_height*3;
	unsigned char *image_buffer = new unsigned char [image_size];

	bench_timer.start();
	int bench_count = 35;
	for(int i = 0; i < bench_count; i++)
	{
		int jpeg_result = tjDecompress2(jpeg, (unsigned char*)jpeg_data.data(), jpeg_data.size(), image_buffer, jpeg_width, jpeg_width*3, jpeg_height, TJPF_RGB, 0);
		qDebug() << "frame=" << (i + 1) << "jpeg_result=" << jpeg_result << (tjGetErrorStr());
	}
	qreal elapsed_s = (qreal) bench_timer.elapsed() / 1000;
	qreal fps = ((qreal) bench_count / elapsed_s);

	qDebug() << "turbojpeg FPS=" << fps << "time(s)=" << elapsed_s;

	delete [] image_buffer;
	return true;
}

фактически всего две простые функции :) но поддерживается и libjpeg API, я может чего не понял но мне он показался архаичным или не то смотрел, а новый turbojpeg API - то что надо, ибо просто

I-Love-Microsoft ★★★★★
() автор топика
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)
Ответ на: комментарий от AF

да, за счет sse2 и т.п. - поток один и во время моего теста только одно из 6 ядер используется на 100% а остальные 5 по нулям (смотрел в htop)

сохранял через QImage в bmp - декодирует правильно и я получил 190 fps 1024x768

чему несказанно рад ибо с обычным libjpeg получал раз в 5 меньше fps и это крайне усложняло задачу

I-Love-Microsoft ★★★★★
() автор топика

Тебе нужно что-то вроде jitter-buffer'а в VoIP. Буфер, в котором накапливаются кадры и упорядочиваются согласно их порядковому номеру. Сначала ты производишь буферизацию (накапливаешь несколько кадров), затем начинаешь отправлять их на воспроизведение. Варьируя размер буфера ты можешь найти компромисс, когда многопоточный декодер за время <= T успеет декодировать несколько кадров с последовательными порядковыми номерами, которые воспроизводятся за время T.

m0rph ★★★★★
()
Ответ на: комментарий от m0rph

Но это все актуально, если стоит задача воспроизведения с минимальными задержками. Иначе ты просто можешь задать размер буфера достаточно большим.

m0rph ★★★★★
()
Ответ на: комментарий от m0rph

задержки мне крайне не желательно увеличивать, поэтому такой буфер не подходит, но за идею спасибо

I-Love-Microsoft ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.