Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Чтение сетевых данных без readyread()
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt Ввод/Вывод, Сеть. Межпроцессное взаимодействие
KuvshinoF
class MyClass:: public QThread()
{
  ...
  void run();
  QTimer   DataTimer;
  QUDPSocket socket;
  QByteArray array;
  short addr, port;

public slots:
  void myslot();
  void noData();
}
////////////////////////////////////////////////////////////
MyClass::MyClass()
{
  
}
///////////////////////////////////////////////////////////
void MyClass::run()
{
   DataTimer.setInterval(3000);
   connect(&DataTimer, SIGNAL(timeout()), this, SLOT(noData()));
   QTimer timer;
   connect(&timer, SIGNAL(timeout()), this, SLOT(myslot()), Qt::DirectConnection);
   timer.start(1000);
   exec();
}
///////////////////////////////////////////////////////////

void MyClass::myslot()
{
   if (socket.hasPendingDatagrams())
  {
     DataTimer.stop();
     int size = socket.bytesAvailable();
     array.resize(size);
     socket.readDatagram(array.data(), size, &addr, &port);
     // обработка данных
     DataTimer.start();
  }
}
///////////////////////////////////////////////////////////

void MyClass::noData()
{

}
///////////////////////////////////////////////////////////

Задача следующая - постоянно корректно читать сетевые данные (предполагается при запуске потока запускать таймер вычитывания (если они есть конечно) раз в секунду данных из сети). Пример выше не работает - говорит "timer cannot be started from another thread". DataTimer обязателен для некой обработки ситуации отсутствия сетевых данных. И как лучше читать данные - как в примере выше или вместо if сделать while с int size=socket.pendingdatagramsize();? Или лучше как-то по-другому считывать данные? (пробовал вместо таймера запуска чтения данных использовать while(1) {чтение данных} прямо в run, но тогда возникает та же ошибка с таймером DataTimer, который обязателен)
Алексей1153
KuvshinoF, объект MyClass создаётся в другом потоке, нежели где будет работать run. Следовательно, поле класса - тоже будет жить там же, где объект.

в данном случае проблему можно решить так:
поле класса QTimer DataTimer; - убрать.
В run объявить локальную переменную QTimer DataTimer;

Также обратить внимание на:
QUDPSocket socket; - возможно, нужно синхронизировать доступ к этому полю класса
QByteArray array; - возможно, нужно синхронизировать доступ к этому полю класса
short addr, port; - возможно, нужно синхронизировать доступ к этим полям класса. Также их нужно инициализировать

а я бы так вообще сделал бесконечный цикл внутри void MyClass::run() без вызова exec() , а в цикле подпинывал бы eventDispatcher() :)
KuvshinoF
1. Как же я тогда локальную переменную QTimer DataTimer буду использовать в другом слоте чтения данных myslot? Как мне узнавать момент отсутствия данных (думал сделать таймером с таймаутом через 3 сек.)
2. Что значит (как сделать) синхронизировать доступ?
3. Можно примерчик на подпинывание eventDispatcher() ?
Алексей1153
1 - ну, ок, можно оставить полем, однако создать объект таймера нужно в run:

class MyClass:: public QThread()
{
...
private:
  std::unique_ptr<QTimer> DataTimer;
....
};

void MyClass::run()
{
   DataTimer=std::make_unique<QTimer>();
   connect(&DataTimer.get(), SIGNAL(timeout()), this, SLOT(noData()));
   ...
   ...
   DataTimer->start(3000);
   exec();
}

void MyClass::myslot()
{
   if (socket.hasPendingDatagrams())
  {
     if(DataTimer)DataTimer->stop();
    
     ...
     ...

     if(DataTimer)DataTimer->start();
  }
}


2 - я про межпоточную синхронизацию (возможно, она тут и не требуется, я же не знаю, как это всё у тебя в коде используется)

3 -

#include <QAbstractEventDispatcher>

void .....::run()
{
    while(!isInterruptionRequested())
    {
        if(!eventDispatcher()->processEvents(QEventLoop::AllEvents))
        {
             //никаких сообщений сейчас не было.
             //Тут по надобности можно чуть притормозить поток,
             //например, вызвать
             //msleep(1);
        }
    }
}
KuvshinoF
2. А обязательно создавать умный указатель? ( у меня std не видит метод make_unique)
Если объявить обычный указателеь в хедере, а сделать ему new в run - все равно будет "timers cannot be started from another thread"
Алексей1153
KuvshinoF, заголовок #include<memory> включен? Стандарт C++11 или больше включен в настройках?

умный указатель удобнее в плане того, что утечки не будет по невнимательности

Цитата(KuvshinoF @ 23.4.2021, 17:42) *
Если объявить обычный указателеь в хедере, а сделать ему new в run - все равно будет "timers cannot be started from another thread"

нет, с обычным указателем тоже должно сработать
KuvshinoF
#include<memory> включен, иначе бы я не смог бы объявить std::unique_ptr<QTimer>, только make_unique std не видит...В pro-файле прописан с++11 в QMAKE_LFLAGS.
Ну вот с обычным указателем не работает - видимо вообще нельзя запускать таймер в run...или можно?
Алексей1153
KuvshinoF, make_unique в C++14 добавлен. А вообще - смело включай 17, а то он уже слегка устаревать начиниет ))

если не разрешают новые стандарты, тогда так

DataTimer.reset(new QTimer);


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

но в доке написано так
Цитата
In multithreaded applications, you can use QTimer in any thread that has an event loop. To start an event loop from a non-GUI thread, use QThread::exec(). Qt uses the timer's thread affinity to determine which thread will emit the timeout() signal. Because of this, you must start and stop the timer in its thread; it is not possible to start a timer from another thread.
KuvshinoF
1. Пытаюсь сделать чтение данных без таймера - в run в бесконечном while делаю udpsocket.readDatagram() - выдается ошибка
"socket notifiers cannot be enabled or disabled from another thread" - как это поправить
2. Как при таком методе считывания (п.1) можно ловить (если не таймером) момент отсутствия данных?
Алексей1153
Цитата(KuvshinoF @ 26.4.2021, 19:55) *
udpsocket.readDatagram() - выдается ошибка
"socket notifiers cannot be enabled or disabled from another thread" - как это поправить

такая же песня, что была с QTimer DataTimer;


Цитата(KuvshinoF @ 26.4.2021, 19:55) *
ак при таком методе считывания (п.1) можно ловить (если не таймером) момент отсутствия данных?

элементарно: если udpsocket.hasPendingDatagrams() вернёт false, значит данных нет ))

и если processEvents (пост №4) вернул false, значит не было никакой движухи. Тогда можно небольшой слип вызвать

------------------
если не получается, то прикрепи демонстрационный проект, чтобы было с чем покопаться.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.