LINUX.ORG.RU

QTcpSocket в QThread

 , ,


1

2

Написал вначале QTcpSocket в основном потоке и было все великолепно, стал переносить в поток и понеслось по трубам. Сначала почему-то перестало подключаться по URL(только по IP), я удивился конечно, но думаю ладно. Потом передача данных перестала работать. Стал смотреть в чем дело, а оно только до ConnectingState стало доходить. На серваке accept срабатывает нормально, но передача данных - глухо. В инете советуют вызвать exec на текущем QThread, но когда я это делаю, то у меня сигналы перестают работать. :) Что за ерунда? Спасайте люди добрые.

★★

Код в студию же. Лечить по фото не умеем.

Так могу сказать (если правильно помню), что QTcpSocket должен создаваться и использоваться в одном и том же потоке.

grondek
()
Последнее исправление: grondek (всего исправлений: 1)

Для многопоточных приложений используй SObjectizer. Отличная библиотека для цпп! И это не шутки!

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

man moveToThread()

А можно поподробнее, что это даст? QTcpSocket создаю и использую конечно же в отдельном потоке.

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

С moveToThread() разобрался. Но теперь я не понимаю, что мне с этим делать. exec() вызывать нужно, чтобы включилась очередь событий потока, без этого не представляю как осуществлять коммуникацию между потоками. Но exec() блокирующая и мне уже негде осуществлять мой бесконечный цикл, а мне это необходимо. Вот понаделали, не пойми как использовать. Мне нужен exec(), но не блокирующий.

Booster ★★
() автор топика
Последнее исправление: Booster (всего исправлений: 1)
Ответ на: комментарий от anonymous

Это я уже успел прочесть :) Эх чую придется мне свою очередь городить, на ненавистных синхро примитивах. Но в qt написано, что без событий QTcpSocket нормально не работает. Правда не понятно, нахрена ему события потока в котором он был создан.

Booster ★★
() автор топика
Последнее исправление: Booster (всего исправлений: 1)
Ответ на: комментарий от Booster

Большая часть путаницы происходит из-за того, что QThread используется как абстракатный класс. Такуим образом, единсветнный путь использования Qthread - это создание его подкласса и переопределение метода run(). И это действительно было так, до версии Qt 4.4, начиная с которой метод QThread::run() получил реализацию по умолчанию, следовательно необходимость в создание потомков класса QThread отпала. Главной причиной этому послужил тот факт, что создание потомков класса QThread может препятствовать использованию слотов подклассом.

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

Зачем цитируешь? Сказал же что прочел эту статью и понял, но что делать в моем случае все равно не понимаю.

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

Что? Мы о разных вещах говорим. События не работают и в 5.5 без exec(). Пример не нужен. Мне нужно выполнять бесконечную операцию в цикле, в отдельном потоке и при этом очередь сигналов тоже нужна. exec() блокирующий и не позволяет мне гонять бесконечный цикл. И если я правильно понимаю QTcpSocket какого-то рожна тоже нужна очередь в потоке в котором он был создан, но тут не уверен.

Booster ★★
() автор топика
Ответ на: комментарий от Booster
class TcpParser : public QObject
{
    Q_OBJECT
public:
    TcpParser()
    {
        moveToThread(&t);
        t.start();
        QMetaObject::invokeMethod(this,"init_inthread",Qt::BlockingQueuedConnection);
    }
    ~TcpParser()
    {
        QMetaObject::invokeMethod(this,"close_inthread",Qt::BlockingQueuedConnection);
        t.quit();
        t.wait();
    }
private slots:
    void readTcp()
    {
        while(tcp->bytesAvailable() > 0)
        {
            rxBuff.append(tcp->readAll());
        }
        parseTcp();
    }
    void parseTcp()
    {
        if(rxBuff.size() < MESS_MIN_SIZE) return;
        ...
        emit...
        rxBuff.remove(0,...);
        QMetaObject::invokeMethod(this,"parseTcp",Qt::QueuedConnection);
    }
private:
    QThread t;
    Q_INVOKABLE void init_inthread()
    {
        tcp = new QTcpSocket();
        tcp->connectToHost(...);
        connect(tcp,&QTcpSocket::readyRead,this,&TcpParser::readTcp,Qt::QueuedConnection);
    }
    Q_INVOKABLE void close_inthread()
    {
        delete tcp;
    }
    QTcpSocket* tcp;
    QByteArray rxBuff;
}

например

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

И где же здесь бесконечный цикл? Без него я прекрасно понимаю как сделать. Должен быть бесконечный цикл, который периодически может отвлекаться на постороннее, но основную массу времен должен крутиться именно он. Неужели я так плохо объясняю?

Booster ★★
() автор топика
Ответ на: комментарий от Booster
class TcpParser : public QObject
{
    Q_OBJECT
public:
    TcpParser()
    {
        moveToThread(&t);
        t.start();
        QMetaObject::invokeMethod(this,"init_inthread",Qt::BlockingQueuedConnection);
    }
    ~TcpParser()
    {
        QMetaObject::invokeMethod(this,"close_inthread",Qt::BlockingQueuedConnection);
        t.quit();
        t.wait();
    }
private slots:
    void readTcp()
    {
        while(tcp->bytesAvailable() > 0)
        {
            rxBuff.append(tcp->readAll());
        }
        parseTcp();
    }
    void parseTcp()
    {
        if(rxBuff.size() < MESS_MIN_SIZE) return;
        ...
        emit...
        rxBuff.remove(0,...);
        QMetaObject::invokeMethod(this,"parseTcp",Qt::QueuedConnection);
    }
    void connected()
    {
        QMetaObject::invokeMethod(this,"iteration",Qt::QueuedConnection);
    }
    void iteration()//бесконечный цикл
    {
        ...
        tcp->write(...);
        if(tcp->state() == QTcpSocket::ConnectedState)
        {
            QMetaObject::invokeMethod(this,"iteration",Qt::QueuedConnection);
        }
    }
private:
    QThread t;
    Q_INVOKABLE void init_inthread()
    {
        tcp = new QTcpSocket();
        tcp->connectToHost(...);
        connect(tcp,&QTcpSocket::connected,this,&TcpParser::connected,Qt::QueuedConnection);
        connect(tcp,&QTcpSocket::readyRead,this,&TcpParser::readTcp,Qt::QueuedConnection);
    }
    Q_INVOKABLE void close_inthread()
    {
        delete tcp;
    }
    QTcpSocket* tcp;
    QByteArray rxBuff;
}
anonymous
()
Ответ на: комментарий от Booster

Ну получи диспетчера событий через QThread::eventDispatcher(), а потом вызывай в своём цикле его processEvents() не?

http://doc.qt.io/qt-5/qthread.html#eventDispatcher

Ну и в принципе анонимус правильно говорит - в exec нет необходимости.

asaw ★★★★★
()
Последнее исправление: asaw (всего исправлений: 2)
Ответ на: комментарий от anonymous

exec так или иначе присутствует всегда, вся только разница что его теперь не надо пихать самому.

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

Ещё можно QCoreApplication::processEvents() из цикла соответствующего потока вызывать - тогда эта функция будет обрабатывать события для этого потока.

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

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

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

Вот и не пихай, сделай как в примере. run() переопределять не нужно. От QThread наследоваться тоже.

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

Вообще с этим event loop это паттерн Actor, а ОП зачем-то в его event loop хочет ещё какую-то свою обработку делать. Плохо паттерны мешать. Либо одно не будет хорошо работать, либо второе.

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

Огромное спасибо. Thread::eventDispatcher()::processEvents работает великолепно. QTcpSocket стал работать как и положено. Это все что мне было нужно.

Booster ★★
() автор топика

Это я уже успел прочесть :) Эх чую придется мне свою очередь городить, на ненавистных синхро примитивах.

Ты прочитал но не понял - так точнее ;) moveToThread дает почти идеальный способ работы в потоках без явного задействования синхро-примитивов... Что может быть вкуснее? Но помни что с объектом, над которым сделали moveToThread можно безопасно работать лишь через сигналы-слоты, а если надо напрямую дернуть слот то используй QMetaObject::invokeMethod + QueuedConnection...

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

Паттерны это всего лишь паттерны, задачи бывают разные.

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

Поэтому, луше ТС отговорить делать не правильно, а не предлагать ему сомнительные методы, пусть они и решат его проблему. ;)

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

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

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

Я же написал, что мне был нужно. :) «Стандартный» подход у меня не канает. У меня цикл крутиться всю жизнь приложения и события мне тоже нужны. События здесь играют роль вспомогательную.

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

+1, может человек медицинскую технику делает, пациентами можем стать мы сами... =))) Так что да, только правильные методы! :)

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

Балин, как? Я могу отправить бесконечный цикл в очередь событий, но как я получу другие события? Это событие заблокирует все остальные.

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

Нужно представить бесконечный цикл по другому. Посмотри внимательно на пример анонимуса и отвлекись от «мне обязательно нужен while( true )».

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

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

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

Вы просто зациклились на enterprise приложениях. В играх/симуляторах к примеру данный подход применяется повсеместно. Там бесконечный цикл является главнейшим объектом.

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

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

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

Из какого моего цикла? Можно пример?

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

Вот об этом мы тебе и говорим. Бесконечный цикл и спрятан в exec - он есть из коробки. А ты пытаешся добавить еще свой.

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

Таймер это онанизм, бесконечный цикл это рабочая лошадка, простой здесь недопустим. Самому класть, это через пользовательский ввод что-ли? Не подходит, пользователя вообще может не быть.

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

И что мне этот цикл дает, если они ничего полезного мне не делает, а только диспатчит события.

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