Russian Qt Forum
Ноябрь 23, 2024, 05:38 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Работа с потоками  (Прочитано 10983 раз)
zayac_val
Гость
« : Январь 30, 2009, 19:32 »

Помогите разобраться с потоками.
Хочу написать клиент-серверное приложение, и по задумке каждый вновь создаваемый сокет должен работать в отдельном потоке. Работа потока начинается с выполнения функции run(), в котрой я и создаю свой сокет:
Код:
class Socket : public QTcpSocket
{
  Q_OBJECT
public:
   ClientServer *window;
   Socket(int sockDeskr,QObject *parent);
public slots:
   void read();
   void read_error();
   void deleteLater();
   void write();

};

class Thread : public QThread
{
  Q_OBJECT
public:
  ClientServer *window;
  Thread(int sockDeskr,QObject *parent);
  void run();
private:
   int sockDeskr;
};

Socket::Socket(int sockDeskr,QObject *parent):QTcpSocket(parent)
{
    window=(ClientServer *)parent;
     this->setSocketDeskriptor(sockDeskr);
  connect(this,SIGNAL(readyRead()),this,SLOT(read()));
  connect(this,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(read_error()));
  connect(window->pushButton_3,SIGNAL(clicked()),this,SLOT(write()));
}

void Socket::read()
{
  QByteArray bar=this->readAll();
          QString str;
          str.append(bar);
          window->textEdit->setText(str); 
}

void Socket::read_error()
{
  QMessageBox *mb=new QMessageBox(this);
          mb->setText(codec->toUnicode("Ошибка сокета: ")+this->errorString());
          mb->exec();
}

void Socket::write()
{
  QByteArray bar;
  bar.append(window->textEdit->toPlainText());
  this->write(bar);
}

/////////////////////////////////////////////////////////<-----------Thread-------->/////////////////////////
void Thread::Thread(int sockDeskr,QObject *parent)
{
  this->sockDeskr=sockDeskr;
  window=(ClientServer *)parent;
}

void Thread::run()
{
Socket *soc=new Socket(sockDeskr,window);
}
Сокет при такой реализации будет работать в отдельном потоке, или я в потоке просто создаю экземпляр сокета и не более, и для правильной работы мне надо реализовывать слоты для сокета в классе Thread.
Записан
Dendy
Гость
« Ответ #1 : Январь 30, 2009, 20:48 »

Вижу вы даже не пробовали запускать своё приложение. Во-первых, зачем вы наследуетесь от QTcpSocket? Во вторых создавать и использовать экземпляры QWidget можно только в главном потоке. Поток должен знать только о своей задаче, и ни про что более вроде GUI классов.
Записан
zayac_val
Гость
« Ответ #2 : Февраль 02, 2009, 15:28 »

Вижу вы даже не пробовали запускать своё приложение. Во-первых, зачем вы наследуетесь от QTcpSocket? Во вторых создавать и использовать экземпляры QWidget можно только в главном потоке. Поток должен знать только о своей задаче, и ни про что более вроде GUI классов.

Приложение действительно не запускал, т.к.  хотелось сначала правильно организовать структуру программы. От  QTcpSocket наследуюсь, т.к. хотелось чтоб работа сокета и все нужные для этого слоты были реализованы в отдельном классе. Раз использовать экземпляры QWidget в дочернем потоке нельзя, то на сколько я понимаю отдавать результаты работы надо, через какой-то буфер. Но меня больше интересует методы объекта создаваемого в функции run() класса Thread будут выполнятся в дочернем потоке, или в основном ?
Записан
Dendy
Гость
« Ответ #3 : Февраль 02, 2009, 15:35 »

Цитировать
От  QTcpSocket наследуюсь, т.к. хотелось чтоб работа сокета и все нужные для этого слоты были реализованы в отдельном классе.

Для этого наследоваться не нужно.

Цитировать
Но меня больше интересует методы объекта создаваемого в функции run() класса Thread будут выполнятся в дочернем потоке, или в основном ?

События обьекта будут выполняться в том потоке, которому принадлежит обьект. А принадлежит он тому потоку, в котором был создан.
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #4 : Февраль 02, 2009, 15:41 »

2 zayac_val , посмотри примерчик http://www.prog.org.ru/topic_8455_30.html

там в самом конце пример... если яправильно понял

попробуй этот же пример, предварительно заккоментировав по очереди строчки:
Код:
    tB->cB->moveToThread(tB);
    tA->cA->moveToThread(tA);

и посмотри в чем разница

ЗЫ: может пригодится Улыбающийся
ЗЫЗЫ: тока в этом примере память утекает куда-то Улыбающийся
« Последнее редактирование: Февраль 02, 2009, 16:22 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
zayac_val
Гость
« Ответ #5 : Февраль 03, 2009, 20:33 »

У меня клиент-серверное приложение, сокет(клиента) я создал в основном потоке, при коннекте к серверу в нем создается дочерний поток в котором создается сокет, предназначенный для общения с сокетом из основного потока. Проблема как обмениваться сигналами между потоками. Т.е. когда один сокет вызывает функцию write(), другой сокет сигнал readyRead не получает.
Записан
ритт
Гость
« Ответ #6 : Февраль 03, 2009, 21:02 »

т.е.
Код:
void Thread::Thread(int sockDeskr,QObject *parent)
{
  this->sockDeskr=sockDeskr;
  window=(ClientServer *)parent;
}

void Thread::run()
{
Socket *soc=new Socket(sockDeskr,window);
}
//...
QTcpSocket* socket = new QTcpSocket(this);
socket->connectToHost(...);
Thread* thread = new Thread(socket->socketDescriptor(), this);
и вопрос - почему soc->read() (в потоке thread) не срабатывает на socket->write(...) (в потоке main)?
я правильно всё понял?
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #7 : Февраль 03, 2009, 22:03 »

BWT:

Код
C++ (Qt)
Socket *soc=new Socket(sockDeskr,window);

Socket создается во вспомогательном потоке, parent (window) создается в главном потоке. Это случайно не противоречит:

Цитировать
The child of a QObject must always be created in the thread where the parent was created.
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
zayac_val
Гость
« Ответ #8 : Февраль 04, 2009, 09:49 »

т.е.
Код:
void Thread::Thread(int sockDeskr,QObject *parent)
{
  this->sockDeskr=sockDeskr;
  window=(ClientServer *)parent;
}

void Thread::run()
{
Socket *soc=new Socket(sockDeskr,window);
}
//...
QTcpSocket* socket = new QTcpSocket(this);
socket->connectToHost(...);
Thread* thread = new Thread(socket->socketDescriptor(), this);
и вопрос - почему soc->read() (в потоке thread) не срабатывает на socket->write(...) (в потоке main)?
я правильно всё понял?


Да, именно так. И еще вопрос из той же облсти, как сигналы от формы, например нажатие кнопки, передавать в вспомогательный поток ?
Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #9 : Февраль 04, 2009, 10:22 »

Цитировать
У меня клиент-серверное приложение, сокет(клиента) я создал в основном потоке, при коннекте к серверу в нем создается дочерний поток в котором создается сокет, предназначенный для общения с сокетом из основного потока.

я шот не понял..
1. а зачем спри коннекте к серверу создавать в потоке еще один сокет?
2. какой смысл обмена сигналами между сокетами одного приложения ?

2 zayac_val , и посмотри все-таки ту ссылку шо я привел.. т.к там именно то что тебе нужно (ИМХО).. и не важно что там не сокеты! Улыбающийся
т.к. там рассматривался "общий" пример по сути принципа создания потоков и выполнению методов в ЭТИХ потоках, а не в главном потоке!
« Последнее редактирование: Февраль 04, 2009, 10:42 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
ритт
Гость
« Ответ #10 : Февраль 04, 2009, 16:26 »

Да, именно так.
readyRead() клиентского сокета эмитится, когда сокет на сервере пишет данные, но уж никак не тогда, когда сам клиентский сокет пишет данные. поэтому такой бред работать не будет.

И еще вопрос из той же облсти, как сигналы от формы, например нажатие кнопки, передавать в вспомогательный поток ?
читай QObject::connect - это базовый материал, без знания которого вообще не стОит лезть в кутэ.
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #11 : Февраль 05, 2009, 13:59 »

2 zayac_val: а чего бы вам не поизучать  QTDIR/examples/network/fortuneclient и QTDIR/examples/network/threadedfortuneserver?
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
zayac_val
Гость
« Ответ #12 : Февраль 09, 2009, 16:37 »

Вся беда была из-за того, что не был запущен цикл обработки сообщений, т.е. метод exec(); в функции run(); потока. 
       Dendy говорил, что :" создавать и использовать экземпляры QWidget можно только в главном потоке", но, на сколько я понииаю, использовать в второстепенном потоке указатель на форму  для соединения сигналов от формы с слотами потока, и наоборот, для соединения сигналов от потока с слотами формы никто не запрещает, или я опять неправ ? Непонимающий
Записан
Dendy
Гость
« Ответ #13 : Февраль 12, 2009, 10:04 »

Соединения сигналов со слотами можно делать из любых потоков. Как и любые другие классы - потомки QWidget могут иметь потокобезопастные методы, которые должны оговариваться отдельно в документации к конкретному классу.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.231 секунд. Запросов: 23.