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

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

Страниц: 1 [2] 3 4 ... 8   Вниз
  Печать  
Автор Тема: Очереди, самодельные сигналы  (Прочитано 71391 раз)
labview
Гость
« Ответ #15 : Август 04, 2010, 19:42 »

Вот именно, что незачем. Видимо я что то попутал. Мне кажется, мне нужен сигнал, а не семафор.

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

Код:
#include <iostream>
#include <QThread>
#include <QList>
#include <QMutex>

class MyQueue
{
    QMutex lock;
    QList <int> list;
public:
    int i;
    int getLast() {lock.lock(); i = list.last(); lock.unlock(); return i;}
    void addLast(int i) {lock.lock(); list.push_back(i); lock.unlock();}
};

class WriterThread : public QThread {

public:
  WriterThread(MyQueue *queue, QObject *parent = 0);
private:
  MyQueue *myQueue;
protected:
  void run();
};

WriterThread::WriterThread(MyQueue *queue, QObject *parent)
        : QThread(parent), myQueue(queue)
{
}

void WriterThread::run()
{
    for(int  i = 0; i <= 100; i++)
    {
        myQueue->addLast(i);
        this->msleep(100);
    }
}

class ReaderThread : public QThread {

public:
  ReaderThread(MyQueue *queue, QObject *parent = 0);
private:
  MyQueue *myQueue;
protected:
  void run();
};

ReaderThread::ReaderThread(MyQueue *queue, QObject *parent)
        : QThread(parent), myQueue(queue)
{
}

void ReaderThread::run()
{
    int  i = 0;
    while(i < 100)
    {
        i = myQueue->getLast();
        std::cout <<  i  << std::endl;
    }
}

int main()
{
  MyQueue mq;
  WriterThread a(&mq);
  ReaderThread b(&mq);
  a.start();
  b.start();
  a.wait();
  b.wait();
}

Мне просто нужен сигнал (event) о том, что первый поток вложил в очередь данные, вот и всё.
Каким способом это реализовать?
Записан
labview
Гость
« Ответ #16 : Август 04, 2010, 20:11 »

Извините, может быть я неправильно выразился.

В общем мне нужна система сигналов и слотов, но с доработками.
- Сигналы должны буферизоваться, пока не будут обработаны (наверное так оно и есть уже в Qt)
- Размер буфера для сигналов хотелось бы задавать самому
- При переполнении размера буфера с сигналами должна быть возможность удалить первый и в конец буфера добавить новый
- Так же хотелось бы опустошить буфер с сигналами, так и не обработав их

Поэтому я решил взять очередь для хранения сигналов, так как ей можно управлять.
Но мне как бы нехватает информации о том, что в очередь был добавлен сигнал, чтобы поток-получатель смог на него отреагировать.
« Последнее редактирование: Август 04, 2010, 20:14 от labview » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #17 : Август 04, 2010, 20:42 »

А нужно ли Вам в читающей нитке брать run на себя? Пока Вы имеете от этого одни неудобства. Напр. что должен вернуть getLast если список пуст? Как организовать ожидание если данных для обработки пока нет? Воэиться с этим оправдано только если нужно выжать скорость. Иначе намного проще посылать этой нитке сигналы (коннект с флагом QueuedConnection). По умолчанию run вызовет exec, сигналы будут приниматься

Локи все равно нужны если данные общие для 2 и более ниток. Выглядеть может примерно так (не проверял, ошибки возможны)

Код
C++ (Qt)
#include <iostream>
#include <QThread>
#include <QList>
#include <QMutex>
 
class MyQueue
{
   QMutex mutex;
   QList <int> list;
public:
   bool getLast( int & i )
   {
      QMutexLocker lock(&mutex);
      if (!list.size()) return false;
      i = list.last();
      return true;
   }
 
   void addLast( int i )
   {
      QMutexLocker lock(&mutex);
      list.push_back(i);
   }
};
 
class WriterThread : public QThread {
 
public:
 WriterThread(MyQueue *queue, QObject *parent = 0);
signals:
 void NewData( void );  
 void EndJob  ( void );  
private:
 MyQueue *myQueue;
protected:
 void run();
};
 
WriterThread::WriterThread(MyQueue *queue, QObject *parent)
       : QThread(parent), myQueue(queue)
{
}
 
void WriterThread::run()
{
   for(int  i = 0; i <= 100; i++)
   {
       myQueue->addLast(i);
       emit NewData();
       this->msleep(100);
   }
   emit EndJob();
}
 
class ReaderThread : public QThread {
 
public:
 ReaderThread(MyQueue *queue, QObject *parent = 0);
public slots:
 void NewData( void );
private:
 MyQueue *myQueue;
};
 
ReaderThread::ReaderThread(MyQueue *queue, QObject *parent)
       : QThread(parent), myQueue(queue)
{
}
 
void ReaderThread::NewData( void )
{
   int i;
   if (myQueue->getLast(i))
     std::cout <<  i  << std::endl;
}
 
int main()
{
 MyQueue mq;
 WriterThread a(&mq);
 ReaderThread b(&mq);
 QObject::connect(&a, SIGNAL(NewData()), &b, SLOT(NewData()), Qt::QueuedConnection);
 QObject::connect(&a, SIGNAL(EndJob()), &b, SLOT(quit()), Qt::QueuedConnection);
 a.start();
 b.start();
 a.wait();
 b.wait();
}
« Последнее редактирование: Август 04, 2010, 21:18 от Igors » Записан
SimpleSunny
Гость
« Ответ #18 : Август 04, 2010, 21:04 »

Если задания только раздаются и обрабатываются только в принимающем потоке и соединение типа "много писателей, один выполняющий", то можно попробовать вообще без локов.

Код
C++ (Qt)
#include <QThread>
#include <QList>
 
class WriterThread : public QThread
{
Q_OBJECT
 
public:
 WriterThread(QObject *parent = 0) : QThread(parent) {};
 
signals:
 void NewData(int);
 
protected:
 void run();
};
 
void WriterThread::run()
{
   for(int  i = 0; i <= 100; ++i)
       emit NewData(i);
}
 
class ReaderThread : public QThread
{
public:
 ReaderThread(QObject *parent = 0) : QThread(parent) {};
 
public slots:
 void NewData(int i);
 
private:
 QList <int> list;
};
 
void ReaderThread::NewData(int i)
{
   //Тут обрабатывать очередь
   list.push_back(i);
   if (list.size > listMaxSize)
       list.removeFirst();
   //и т. д. и т. п.
}
 
int main()
{
 WriterThread a();
 ReaderThread b();
 connect(&a, SIGNAL(NewData(int)), &b, SLOT(NewData(int)), Qt::QueuedConnection);
 a.start();
 b.start();
 a.wait();
 b.wait();
}
 
« Последнее редактирование: Август 04, 2010, 21:10 от SimpleSunny » Записан
labview
Гость
« Ответ #19 : Август 04, 2010, 21:17 »

Спасибо конечно, но не один из последних примеров не компилируется. В примере Igors пишет, что connect не декларирован в main.

А если добавляю "QObject::", то пишет undefined reference to WriterThread::NewData() и undefined reference to WriterThread::EndJob().

Буду разбираться.
« Последнее редактирование: Август 04, 2010, 21:19 от labview » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #20 : Август 04, 2010, 21:19 »

QObject::connect  Улыбающийся
Записан
labview
Гость
« Ответ #21 : Август 04, 2010, 22:18 »

Не компилируется, я что то ещё забыл?

Цитировать
debug/main.o: In function `ZN12WriterThreadC2EP7MyQueueP7QObject':
D:/C++/QThread-build-desktop/../QThread/main.cpp:43: undefined reference to `vtable for WriterThread'
debug/main.o: In function `ZN12WriterThreadC1EP7MyQueueP7QObject':
D:/C++/QThread-build-desktop/../QThread/main.cpp:43: undefined reference to `vtable for WriterThread'
debug/main.o: In function `ZN12ReaderThreadC2EP7MyQueueP7QObject':
D:/C++/QThread-build-desktop/../QThread/main.cpp:71: undefined reference to `vtable for ReaderThread'
debug/main.o: In function `ZN12ReaderThreadC1EP7MyQueueP7QObject':
D:/C++/QThread-build-desktop/../QThread/main.cpp:71: undefined reference to `vtable for ReaderThread'
debug/main.o: In function `ZNK15QBasicAtomicIntneEi':
c:/Qt/4.6.3/include/QtCore/../../src/corelib/tools/qlist.h:(.text$_ZN12WriterThreadD1Ev[WriterThread::~WriterThread()]+0xb): undefined reference to `vtable for WriterThread'
c:/Qt/4.6.3/include/QtCore/../../src/corelib/tools/qlist.h:(.text$_ZN12ReaderThreadD1Ev[ReaderThread::~ReaderThread()]+0xb): undefined reference to `vtable for ReaderThread'
collect2: ld returned 1 exit status
mingw32-make.exe[1]: *** [debug/QThread.exe] Error 1
C:\MinGW\bin\mingw32-make.exe: *** [debug] Error 2
Записан
SimpleSunny
Гость
« Ответ #22 : Август 04, 2010, 22:51 »

макрос Q_OBJECT прописали?
Записан
labview
Гость
« Ответ #23 : Август 04, 2010, 23:08 »

Именно поэтому и перестало компилироваться.
Но ладно, я потом уже раскидал дефинирование классов по хедерам, вроде стало лучше, потом появилось сообщение, что EventLoop не работает без QApplication. Оказалось что проект был откунфигурирован под консоль. Переконфигурировал проект, стало компилироваться и выполняться. Но ничего к сожалению не выдаётся.
Сейчас сижу дибагю, не понимаю почему сигнал не emit-ится.

Код:
#ifndef MYQUEUE_H
#define MYQUEUE_H

#include <QList>
#include <QMutex>

class MyQueue
{
    QMutex mutex;
    QList <int> list;
public:
    bool getLast( int & i )
    {
       QMutexLocker lock(&mutex);
       if (!list.size()) return false;
       i = list.last();
       return true;
    }

    void addLast( int i )
    {
       QMutexLocker lock(&mutex);
       list.push_back(i);
    }
};

#endif // MYQUEUE_H

Код:
#ifndef READERTHREAD_H
#define READERTHREAD_H

#include <QThread>
#include "MyQueue.h"

class ReaderThread : public QThread {

Q_OBJECT

public:
  ReaderThread(MyQueue *queue, QObject *parent = 0);
public slots:
  void NewData( void );
private:
  MyQueue *myQueue;
};

#endif // READERTHREAD_H

Код:
#ifndef WRITERTHREAD_H
#define WRITERTHREAD_H

#include <QThread>
#include "MyQueue.h"

class WriterThread : public QThread {

Q_OBJECT

public:
  WriterThread(MyQueue *queue, QObject *parent = 0);
signals:
  void NewData( void );
  void EndJob  ( void );
private:
  MyQueue *myQueue;
protected:
  void run();
};

#endif // WRITERTHREAD_H

Код:
#include <iostream>
#include "QApplication.h"
#include "WriterThread.h"
#include "ReaderThread.h"

WriterThread::WriterThread(MyQueue *queue, QObject *parent)
        : QThread(parent), myQueue(queue)
{
}

void WriterThread::run()
{
    for(int  i = 0; i <= 100; i++)
    {
        myQueue->addLast(i);
        emit NewData();
        this->msleep(100);
    }
    emit EndJob();
}

ReaderThread::ReaderThread(MyQueue *queue, QObject *parent)
        : QThread(parent), myQueue(queue)
{
}

void ReaderThread::NewData( void )
{
    int i;
    if (myQueue->getLast(i))
      std::cout <<  i  << std::endl;
}

int main(int argc, char *argv[])
{
  QApplication app(argc, argv);
  MyQueue mq;
  WriterThread a(&mq);
  ReaderThread b(&mq);
  QObject::connect(&a, SIGNAL(NewData()), &b, SLOT(NewData()), Qt::QueuedConnection);
  QObject::connect(&a, SIGNAL(EndJob()), &b, SLOT(quit()), Qt::QueuedConnection);
  a.start();
  b.start();
  a.wait();
  b.wait();
  return app.exec();
}
« Последнее редактирование: Август 04, 2010, 23:10 от labview » Записан
ufna
Гость
« Ответ #24 : Август 04, 2010, 23:35 »

После того, как добавил этот макрос (а его обязательно добавь, без него сигналы и т.п. работать не будут), сделай clean project, затем qmake, а потом только - сборку проекта. Второй шаг обязателен, т.к. сий глюк втаблов оттуда именно.
Записан
labview
Гость
« Ответ #25 : Август 05, 2010, 01:53 »

Привет!

Мне кажется, я взял задание, которое на моей стадии познания Qt и C++ мне непосильно. Для начала разберусь с системой сигналов и слотов для обмена данными между потоками. А потом, когда мне будет всё до конца ясно, возьмусь за реализацию своей идеи.

Всем на этом огромное спасибо.
Записан
labview
Гость
« Ответ #26 : Август 12, 2010, 02:05 »

Скажите а какой нибудь функции с примерно таким названием "bool WaitOnEvent(event *event, int timeout)" в Qt не существует? Ну чтобы поток замирал на время Timeout, при условии если ивент не приходит? Но если ивент приходит, то сразу же реагировал, т.е. заканчивал выполнение этой функции с возвращением 0.
Записан
galilley
Гость
« Ответ #27 : Август 12, 2010, 06:58 »

Как-то мне надо было реализовать блокирующий read данных из одного потока в другой, чтобы первичный поток засыпал пока функция не будет обработана. Суть была в том, что я из первичого потока вызывал метод объекта, находящегося в основном потоке, там бросал event тому объекту, что я хочу читать, и чтобы он отправил сигнал вторичному потоку, и локал первичный поток семафором. После того, как приходил сигнал с данными от вторичного потока я кидал их в переменную, разблокировал симафор и данные возвращались в первичный поток return-ом.
Может Вам может помочь какая-нить подобная реализация? Или есть методы проще, а я много намутил...
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #28 : Август 12, 2010, 12:05 »

Самый простой способ: запустить нитку, она начнет крутить  свой eventLoop. Когда для нитки есть работа - послать ей сигнал. Нитка выполнит задание, вернет результаты (также через сигнал) и опять уйдет в eventLoop. Для этого в Qt все заточено, дополнительные семафоры не нужны. Просто создавайте и связывайте слоты/сигналы
Записан
labview
Гость
« Ответ #29 : Август 12, 2010, 12:37 »

Но насколько я понял event loop всегда относится к главному потоку и в Qthread не поддерживается.
Или я ошибаюсь?
Записан
Страниц: 1 [2] 3 4 ... 8   Вверх
  Печать  
 
Перейти в:  


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