Здравствуйте, 00011011, Вы писали:
0>Здравствуйте, Zhendos, Вы писали:
Z>>Вот статья от разработчиков Qt по этому поводу: https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong .
0>Низкоуровневые API для многопоточности предполагают наличие некоторой функции создания потока, которой передается в качестве аргумента указатель на гдавную функцию потока и ее аргументы (CreateThread, pthread_create и т.д). Нечто похожее есть в QThread: static QThread *create(Function &&f, Args &&... args). Предлагаете использовать ее? Есть какие-то примеры как надо делать?
Ну все зависит от ваших задач. Я предлагаю только не использовать наследование от QThread.
Пример как это делать самый первый в документации к QThread. Ну и здесь уже в посте
есть другой пример, но с тем же принципом — наследование от QObject.
0>Честно говоря, для меня оказалось удивительно что объекты Qt каким-то образом принадлежат потокам, а не просто существуют в памяти. В чем физический смысл этой принадлежности? Мне кажется, это какое-то усложненение, наверное обусловленное архитектурой Qt. Хотя я об этом где-то прочитал, и по этой причине объявил сокет изначально как локальную переменную в функции потока, а затем оказалось что он нужен и в слоте — поэтому по быстрому переделал в указатель.
Ну теперь вы поняли что это не усложнение, а реально нужная вещь? На примере собственной ошибки.
Пользователь обычно не делает слоты рассчитанными на вызов из разных потоков
одновременно. Поэтому `connect` заботиться об этом, используя информацию о
том что "receiver" и "sender" располагаются в разных потоках, `connect` заботиться
о том, чтобы несмотря на то что сигнал был вызван в потоке в котором живет
"sender", слот будет вызван в потоке "receiver". И никакой "data-race" не будет.
Так же это помогает в отладочной сборке валидировать с помощью assert и "QThread::currentThread"
правильное использование потоков.
И в эту прекрасную картину правильного использования многопоточности не укладывается только
одна вещь — QThread. Вернее его использования с наследованием, интуитивно кажется что
сам QThread должен принадлежать самому себе. Но это не так, по умолчанию
он принадлежит потоку в котором создан.
Здравствуйте, 00011011, Вы писали:
0>Сделал прием udp в отдельном потоке. Но стабильно ловится только первый пакет. 0>Дальше начинается странное — иногда, если походить в отладке, вновь приходим в слот приема. Если без отладки, то не приходит больше одного раза. 0>Ранее реализованный прием без потока работает идеально. В программе отправки уверен, она написана давно и не на Qt, многократно проверена, умеет отправлять и принимать по udp пакеты. В том числе сама себе через локалхост.
class Receiver : public QObject
{
Q_OBJECT
public:
Receiver(QObject *parent);
~Receiver();
unsigned long m_Size = 0;
void start();
public slots:
void doStart();
void onReceive();
private:
QScopedPointer<QUdpSocket> m_pSocket;
};
Здравствуйте, 00011011, Вы писали:
0>Здравствуйте, Zhendos, Вы писали:
Z>> Вообще наследование от QThread это плохой подход в современном Qt. Z>> Все реализовано так, что можно обойтись без этого.
0>Подскажите какие способы есть хорошие. Отдельные потоки мне нужны только из-за требований к высокой часоте обмена, которая скороее всего подвесит GUI, если делать все в одном потоке.
Ну в потоке QThread уже все есть для того чтобы от него не наследовать, а использовать как есть,
это раньше метод run был чисто абстрактный, теперь он вызывает exec.
Теперь есть сигналы finished где можно освобождать
объекты (можно просто связать с QObject::deleteLater),
сигнал started где можно инициализировать в контексте потока.
Основная идея, которую продвигают разработчики Qt, что QThread это класс
для управления потоками, а не класс для асинхронной работы.
Нужно что-то делать в другом потоке, унаследуйте от QObject,
вызовете moveToThread, свяжите сигналы и слоты QThread с этим QObject и вперед.
Сделал прием udp в отдельном потоке. Но стабильно ловится только первый пакет.
Дальше начинается странное — иногда, если походить в отладке, вновь приходим в слот приема. Если без отладки, то не приходит больше одного раза.
Ранее реализованный прием без потока работает идеально. В программе отправки уверен, она написана давно и не на Qt, многократно проверена, умеет отправлять и принимать по udp пакеты. В том числе сама себе через локалхост.
class Receiver : public QThread
{
Q_OBJECT
public:
Receiver(QObject *parent);
~Receiver();
unsigned long m_Size;
protected:
virtual void run();
public slots:
void onReceive();
private:
QUdpSocket *m_pSocket;
};
Здравствуйте, 00011011, Вы писали:
0>Сделал прием udp в отдельном потоке. Но стабильно ловится только первый пакет. 0>Дальше начинается странное — иногда, если походить в отладке, вновь приходим в слот приема. Если без отладки, то не приходит больше одного раза.
1. Вы используете "this" в connect. QThread тоже QObject,
и он имеет связанный с ним поток и этот поток это не он сам. А вот
"socket" создан в самом потоке, в результате не только сигналы
доставляются через очередь сообщения, а не прямым вызовом,
но и есть явная "data-race". Так как "onReceive" вызывается в другом потоке,
а обращается к сокету из потока Receiver.
Вообще наследование от QThread это плохой подход в современном Qt.
Все реализовано так, что можно обойтись без этого.
2. Нужно к другим сигналам подключиться, по крайней мере к тем что сообщают об изменении
состояния и ошибках: errorOccurred/stateChanged
Здравствуйте, Zhendos, Вы писали:
Z> Вообще наследование от QThread это плохой подход в современном Qt. Z> Все реализовано так, что можно обойтись без этого.
Подскажите какие способы есть хорошие. Отдельные потоки мне нужны только из-за требований к высокой часоте обмена, которая скороее всего подвесит GUI, если делать все в одном потоке.
Низкоуровневые API для многопоточности предполагают наличие некоторой функции создания потока, которой передается в качестве аргумента указатель на гдавную функцию потока и ее аргументы (CreateThread, pthread_create и т.д). Нечто похожее есть в QThread: static QThread *create(Function &&f, Args &&... args). Предлагаете использовать ее? Есть какие-то примеры как надо делать?
Я использовал в качестве образца официальный пример corelib/thread/mandelbrot. Там как раз через наследование от QThread. но мне наследование как таковое не нужно (как и сигналы/слоты), мне нужно просто запустить поток, не заморачиваясь с "принадлежностью" объектов к потоку, и наиболее оптимально принимать данные по udp. Поток запускается при старте программы и закрывается при ее завершении (да, нужно чтобы он не зависал при завершении, т.е. все-же какойто механизм корректного завершения).
Честно говоря, для меня оказалось удивительно что объекты Qt каким-то образом принадлежат потокам, а не просто существуют в памяти. В чем физический смысл этой принадлежности? Мне кажется, это какое-то усложненение, наверное обусловленное архитектурой Qt. Хотя я об этом где-то прочитал, и по этой причине объявил сокет изначально как локальную переменную в функции потока, а затем оказалось что он нужен и в слоте — поэтому по быстрому переделал в указатель.