LINUX.ORG.RU

класс QThread и слоты

 ,


0

2

Пытался найти ответ в документации, но немного не догоняю - если у меня работает метод run и крутит поток, то что если моему классу, наследованному от QThread, приходит сигнал в его слот? Что в этот момент происходит с run? Слоты ведь приходят асинхронно, так? Требуется ли использовать QMutex внутри слота, если модифицируются данные, с которыми работает run?

Вот я влепил QMutex в слот и увидел что Qt жалуется и программа падает...

Решил уточнить - что происходит со слотами при работающем run и как защитить данные?

В конструкторе производного класса moveToThread(this) стоит? Обычно слоты выполняются в контексте того потока, который послал сигнал. Если есть moveToThread(this) и слот приаттачен как Qt::QueuedConnection, то он будет выполняеться в том же потоке, что и метод run(), в котором создана очередь событий через exec().

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

хорошо, даже если так, но если я не предусмотрел никаких exec в потоке, ни каких-либо QApplication::processEvents() во время выполнения run, то получается что run для обработки слота может быть прерван в любой момент - так? или он вообще не вызовется если я не буду давать такой возможности?

как я должен написать программу? сделать moveToThread(this) и только после этого использование QMutex будет беспроблемным?

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

я ничего не путаю, сигналы ОС и Qtшные - огромная разница

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

по дефолту я понимаю что эти слоты исполняются в главном потоке - это меня и смущает

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

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

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

В конструкторе производного класса moveToThread(this) стоит?

Так делать крайне не рекомендуется, потому что сломаются сигналы и слоты самого QThread. Объект QThread принадлежит тому потоку, который его создал, потому что он должен иметь возможность управлять им. Хорошей практикой считается создание объекта, наследованного от QObject, в котором размещается весь код потока, и объекта QThread, в который переносится первый объект с помощью moveToThread(). Таким образом весь код потока инкапсулируется в отдельном классе, а объект QThread остаётся в основном потоке (в таком случае даже не всегда необходимо наследовать свой класс от QThread).

gentoo_root ★★★★★
()

Слоты треда, подключаются к сигналам другого треда через Qt::QueuedConnection и поэтому не вызываются напрямую, а вызываются на очередной итерации цикла обработки сообщений треда exec().

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

Тут надо понять что ты хочешь.

1) Если у тебя класс унаследован от QThread и ты производишь постоянно работу в методе run, при этом ты не вызываешь Qt-шный код обработки событий (exec например), то твои слоты никогда не выполнятся в этом потоке (в лучшем случае они будут выполнятся в потоке где имитирован сигнал). Посему тут надо делать по другому без сигналов-слотов.

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

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

Посему тут надо делать по другому без сигналов-слотов.

Как лучше делать для варианта с какой-либо длительной однократной обработкой, после которой поток уже становится не нужен?

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

Как лучше делать для варианта с какой-либо длительной однократной обработкой, после которой поток уже становится не нужен?

Если нужно однократно что-то обработать и выплюнуть результат, при этом НЕ происходит обмен данными между потоком-обработчиком и другими, а результирующие данные забираются из другого потока уже ПОСЛЕ завершения потока-обработчика, то в этом случае нужно просто реализовать свой код в методе QThread::run. Главное начать забирать результирующие данные ПОСЛЕ ЗАВЕРШЕНИЯ потока-обработчика. Надо учитывать, что создание нового потока требует накладных расходов, этот способ желательно использовать если такая обработка запускается достаточно редко.

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

Если нужно обмен данными между потоками во время вычислений, то без QMutex (и, возможно, QWaitCondition) уже не обойтись.

SSZB
()
Ответ на: комментарий от Suigintou

Как лучше делать для варианта с какой-либо длительной однократной обработкой, после которой поток уже становится не нужен?

use QtConcurrent - запустит любую статическую функцию класса или просто функцию как поток - не надо даже своих классов создавать и наследовать - удобно, но разобраться не просто, я парился, но в итоге работает годно :)

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

пожалуйста, покритикуйте!

template< class T>
class misc_mlc
{
public:
	misc_mlc(QMutex *_mutex, T _value)
	{
		mutex = _mutex;
		value = _value;
	}

	T get()
	{
		QMutexLocker locker(mutex);
		return value;
	}

	void set(T _value)
	{
		QMutexLocker locker(mutex);
		value = _value;
	}

private:
	QMutex *mutex;
	T value;
};

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

есть просто QThread, никаких moveToThread нету, в нем есть один слот - в него прилетают данные...

я обернул данные так misc_mlc<bool> data1 и в слоте делаю .set а в run делаю .get и иногда .set

может ли такая конструкция deadlockнуться или данные повредиться?

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

а QMutex не должен быть общим?.. кстати... а мысль :) можно его в один класс запихнуть как ты показал, спасибо за идею

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

а QMutex не должен быть общим?..

конечно должен, для защищаемых данных, а это в данном случае:

T value;

которое лежит в классе, значит и мутекс кладём рядом и горя не знаем

а глобальным мутекс делать - это черевато как раз всякими взаимоблокировками в странных местах

PS кстати, немного не в тему но, обращаю внимание на удобный класс QAtomicInt

shty ★★★★★
()

если у меня работает метод run и крутит поток, то что если моему классу, наследованному от QThread, приходит сигнал в его слот?

мда, закопай свой говнокод и иди учи как раюотают потоки в кутях

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

кстати, немного не в тему но, обращаю внимание на удобный класс QAtomicInt

я о нем думал, но так как у меня данные бывают даже QVarianList с данными на сотню байтов - то int не катит :)

но я был бы очень благодарен за простой пример пользования QAtomicInt - я пытался искать примеры и курить доки - но увы, я так и не понял эти test and set, release и т.п. ... очень надеюсь что есть хорошие примеры работы с этим классом, а я пока не понял как

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

мда, закопай свой говнокод и иди учи как раюотают потоки в кутях

сэр! благодарю! я читал как работают потоки и там четко написано у класса, наследованного от QThread - слоты принадлежат родительскому потоку, а run - это и есть второй поток, и поэтому данные, которые меняются в слоте

qDebug() << "thread" << currentThread();

легко подтверждает мою догадку

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

есть просто QThread, никаких moveToThread нету, в нем есть один слот - в него прилетают данные...

Без ТЗ сложно сказать что тебе надо... Чем тебя не устраивает использование QObject, как описано выше?

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