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

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

Страниц: [1] 2 3 ... 6   Вниз
  Печать  
Автор Тема: [РЕШЕНО] Помогите с задачей производителя/потребителя  (Прочитано 37899 раз)
lolbla2
Гость
« : Март 01, 2012, 17:23 »

Почему-то на разных компах по-разному работает. Потоки такая вещь что они вообще иногда так странно себя ведут однако.
Вообщем, суть в следующем, производитель создаёт символ и передаёт его потребителю. Всё это синхронизировано мютексами и QWaitCondition. Пример взял из документации, пытаюсь его сделать под GUI, ибо там консольное.

Хочу чтобы они у меня в реальном времени символы выводили, то есть производитель создал символ и вывел его, потребитель, получил тоже вывел в textBrowser. ПОка получилось сделать только чтобы по окончанию работы выводился весь буффер символов. В реальном времени не получается что-то, всё повисает.

ВОт код:
consumer
Код
C++ (Qt)
//consumer.h
class Consumer : public QThread
{
   Q_OBJECT
public:
   Consumer();
   void run();
   static void SetDataSize(const int size);
   static void SetBufferSize(const int size);
   static void SetBuffer(char *buf);
   static void SetBufNotEmpy(QWaitCondition *buf);
   static void SetBufNotFull(QWaitCondition *buf);
   static void SetMutex(QMutex *m);
signals:
   void SymbolReceived(char* mes);
private:
   static int DataSize;
   static int BufferSize;
   int numUsedBytes;
   static QMutex *mutex;
   static QWaitCondition *bufferNotEmpty;
   static QWaitCondition *bufferNotFull;
   static char* buffer;
 
//consumer.cpp
Consumer::Consumer()
{
   numUsedBytes = 0;
}
QWaitCondition *Consumer::bufferNotEmpty = NULL;
QWaitCondition *Consumer::bufferNotFull = NULL;
QMutex *Consumer::mutex = NULL;
int Consumer::DataSize = 0;
int Consumer::BufferSize = 0;
char *Consumer::buffer = NULL;
 
void Consumer::SetDataSize(const int size){DataSize = size; }
 
void Consumer::SetBufferSize(const int size){BufferSize = size; }
 
void Consumer::SetBuffer(char *buf){buffer = buf;}
 
void Consumer::SetBufNotEmpy(QWaitCondition *buf){ bufferNotEmpty = buf;}
 
void Consumer::SetBufNotFull(QWaitCondition *buf){bufferNotFull = buf; }
 
void Consumer::SetMutex(QMutex *m){ mutex = m; }
 
void Consumer::run()
{
   for (int i = 0; i < DataSize; ++i) {
       mutex->lock();
       if (numUsedBytes == 0)
           bufferNotEmpty->wait(mutex);
       mutex->unlock();
       qDebug() << buffer[i % BufferSize]; // выводит в дебаге, но хотелось бы тоже самое в гуи выводить, пытаюсь это сделать и    ничего не выводит а вообще прога виснет
       mutex->lock();
       --numUsedBytes;
       bufferNotFull->wakeAll();
       mutex->unlock();
   }
   emit SymbolReceived(buffer);
}
};
 

producer
Код
C++ (Qt)
//producer.h
class Producer : public QThread
{
 
   Q_OBJECT
public:
   Producer();
   void run();
   static void SetDataSize(const int size);
   static void SetBufferSize(const int size);
   static void SetBuffer(char* buf);
   static void SetBufNotEmpy(QWaitCondition *buf);
   static void SetBufNotFull(QWaitCondition *buf);
   static void SetMutex(QMutex *m);
signals:
   void SymbolProduced(char* mes);
private:
   static int DataSize;
   static int BufferSize;
   int numUsedBytes;
   static QMutex *mutex;
   static QWaitCondition *bufferNotEmpty;
   static QWaitCondition *bufferNotFull;
   static char* buffer;
};
//producer.cpp
Producer::Producer()
{
   numUsedBytes = 0;
}
QWaitCondition *Producer::bufferNotEmpty = NULL;
QWaitCondition *Producer::bufferNotFull = NULL;
QMutex *Producer::mutex = NULL;
int Producer::DataSize = 0;
int Producer::BufferSize = 0;
char *Producer::buffer = NULL;
 
void Producer::SetDataSize(const int size){DataSize = size; }
 
void Producer::SetBufferSize(const int size){BufferSize = size; }
 
void Producer::SetBuffer(char *buf){buffer = buf; }
 
void Producer::SetBufNotEmpy(QWaitCondition *buf){ bufferNotEmpty = buf;}
 
void Producer::SetBufNotFull(QWaitCondition *buf){bufferNotFull = buf; }
 
void Producer::SetMutex(QMutex *m){ mutex = m; }
 
void Producer::run()
{
   qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
   for (int i = 0; i < DataSize; ++i) {
       mutex->lock();
       if (numUsedBytes == BufferSize)
           bufferNotFull->wait(mutex);
       mutex->unlock();
 
       buffer[i % BufferSize] = "Hello"[(int)qrand() % 5];
                                                    //здесь по идее надо выводить созданный символ, но виснет гуи
       mutex->lock();
       ++numUsedBytes;
       bufferNotEmpty->wakeAll();
       mutex->unlock();
   }
   emit SymbolProduced(buffer);
}
 

Код
C++ (Qt)
//widget.cpp
const int DataSize = 10000;
const int BufferSize = 8192;
 
QWaitCondition bufferNotEmpty;
QWaitCondition bufferNotFull;
QMutex mutex;
char *usedBuffer;
 
Widget::Widget(QWidget *parent) :
   QWidget(parent),
   ui(new Ui::Widget)
{
   ui->setupUi(this);
   connect(ui->pushButton, SIGNAL(clicked()),this,SLOT(beginWork()));
   producer = new Producer;
   consumer = new Consumer;
 
}
 
Widget::~Widget()
{
   delete ui;
}
void Widget::ConsumerSymbol(char* sym)
{
   QString text;
   for (int i = 0; i < DataSize; ++i)
       text+=QString(sym[i % BufferSize]);
   ui->textBrowser->append(text);
}
void Widget::ProducerSymbol(char* sym)
{
   QString text;
   for (int i = 0; i < DataSize; ++i)
       text+=QString(sym[i % BufferSize]);
   ui->textBrowser_2->append(text);
}
void Widget::beginWork()
{
   ui->textBrowser_2->clear();
   ui->textBrowser->clear();
   usedBuffer = new char[BufferSize];
 
   Producer::SetBufferSize(BufferSize);
   Producer::SetDataSize(DataSize);
   Producer::SetMutex(&mutex);
   Producer::SetBufNotEmpy(&bufferNotEmpty);
   Producer::SetBufNotFull(&bufferNotFull);
   Producer::SetBuffer(usedBuffer);
 
   Consumer::SetBufferSize(BufferSize);
   Consumer::SetDataSize(DataSize);
   Consumer::SetMutex(&mutex);
   Consumer::SetBufNotEmpy(&bufferNotEmpty);
   Consumer::SetBufNotFull(&bufferNotFull);
   Consumer::SetBuffer(usedBuffer);
 
   connect(producer,SIGNAL(SymbolProduced(char*)),this, SLOT(ProducerSymbol(char*)));
   connect(consumer,SIGNAL(SymbolReceived(char*)),this, SLOT(ConsumerSymbol(char*)));
   producer->start();
   consumer->start();
   producer->wait();
   consumer->wait();
}
 

Помогите зделать реалтайм вывод в GUI...
P.S.: чот и такой вариант иногда повисает и ничего не выводит, потоки как-то случайно работают, не понимаю я их порой(( Непонимающий
« Последнее редактирование: Март 03, 2012, 14:51 от lolbla2 » Записан
Bepec
Гость
« Ответ #1 : Март 01, 2012, 17:48 »

ААААААААААААААААААААААААААААААААААААААААААААААААААААААААААААААА....

Мой моск взорвался при виде этого кода...

PS to Пантер - реально...
Записан
lolbla2
Гость
« Ответ #2 : Март 01, 2012, 18:03 »

ААААААААААААААААААААААААААААААААААААААААААААААААААААААААААААААА....

Мой моск взорвался при виде этого кода...

PS to Пантер - реально...

Ну подскажи как правильно) Я не особо давно пользуюсь Qt. Наверно 3 месяц
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #3 : Март 02, 2012, 09:21 »

ААААААААААААААААААААААААААААААААААААААААААААААААААААААААААААААА....

Мой моск взорвался при виде этого кода...

PS to Пантер - реально...
Ну нельзя же так в пятницу с утра с похмелья!
lolbla2, тут даже не знаю, что и сказать. У тебя все неверно.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Март 02, 2012, 12:34 »

lolbla2, тут даже не знаю, что и сказать. У тебя все неверно.
А что неверно? Вроде все правильно (откуда-то списано)
Записан
Bepec
Гость
« Ответ #5 : Март 02, 2012, 13:33 »

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

Вместо изящных, простых конструкций - у тебя чугунная заготовка с афигительным количеством углов, об которые можно биться головой.

PS при попытке разобраться, мозг берёт выходной...
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Март 02, 2012, 14:01 »

Вместо изящных, простых конструкций -
Ну если Вы такой эстет - никто не мешает показать лучшее, более элегантное решение. А охаять чужой код - много ума не надо  Улыбающийся

Кстати, хотя пример из букваря (сейчас посмотрел) мне кажется что он не будет работать правильно с 2 или более consumer'ами

И возвращаясь к первоисточнику - ну и ставьте emit вместо вывода в qDebug() - только обязательно с QueuedConnection 
Записан
Bepec
Гость
« Ответ #7 : Март 02, 2012, 14:06 »

Я прост сегодня переписывал свою многопточку. День работы на вставку комментариев, уборку хлама и придания чистоты "Белизной".

До сих пор под впечатлением Подмигивающий

update:
Если кого и обидел, простите  Показает язык
« Последнее редактирование: Март 02, 2012, 14:12 от Bepec » Записан
lolbla2
Гость
« Ответ #8 : Март 02, 2012, 14:44 »

ААААААААААААААААААААААААААААААААААААААААААААААААААААААААААААААА....

Мой моск взорвался при виде этого кода...

PS to Пантер - реально...
Ну нельзя же так в пятницу с утра с похмелья!
lolbla2, тут даже не знаю, что и сказать. У тебя все неверно.

а что конкретно? предложи тогда свой вариант?

Блин столько комментов, ни одного по теме(((

Вообщем задача чуток поменялась надо вот что:
Разработать приложение, состоящее из двух функциональных частей. Первая время от времени отправляет сообщения (например, это может происходить при нажатии некоторой кнопки, или клавиши на клавиатуре) второй, вторая каким-то образом на них реагирует. Размер буфера передачи между этими частями – 1 сообщение, а первая задача (передатчик) никогда не ждет очистки буфера. Т.е. если вторая часть (приемник) не успевает получить помещенное в буфер сообщение, а уже возникает новое сообщение, то это новое сообщение заменяет старое, а старое - теряется. Здесь передатчик имитирует аппаратное обеспечение СРВ. Время обработки сообщения приемником должно быть 1-2с (можно воспрользоваться функцией Sleep). Необходимо добиться того, чтобы при возникновении 2-3 сообщений подряд (до окончания обработки первого из них) ни одно из них не терялось, т.е. все обрабатывались приемником.

Ожидается использование таких синхронизационных примитивов, как событие, критическая секция или мьютекс. Возможно использование семафоров или семейства Interlocked-функций.

Предлагается такая схема работы. Кроме главного, создаются еще два потока. Один из них с нужной частотой пишет в «буфер» (тот самый, размер которого – одно сообщение) какие-то символы, а другой, как только в буфере появляется символ, читает его оттуда и помещает в какой-то свой буфер. Главный же поток ждет, пока в этом втором буфере появится очередной символ, и затем его «обрабатывает» (например, выводит на экран). Второй буфер должен быть достаточно большим, чтобы вместить 2-3 сообщения (см. условие задачи), где они будут ожидать, пока главный поток их не обработает.


Записан
lolbla2
Гость
« Ответ #9 : Март 02, 2012, 14:48 »

Вместо изящных, простых конструкций -
Ну если Вы такой эстет - никто не мешает показать лучшее, более элегантное решение. А охаять чужой код - много ума не надо  Улыбающийся

Кстати, хотя пример из букваря (сейчас посмотрел) мне кажется что он не будет работать правильно с 2 или более consumer'ами

И возвращаясь к первоисточнику - ну и ставьте emit вместо вывода в qDebug() - только обязательно с QueuedConnection 

а мне и не надо 2 и более
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Март 02, 2012, 15:04 »

Задача у Вас простейшая. Есть общий буфер обмена, передатчик и приемник пишут/читают его  под мутексом. Поэтому если приемник не успеет - передатчик перекроет (как Вам и надо). Записав данные передатчик просто отправляет приемнику сигнал "есть данные" (без параметров). Все.

Блин столько комментов, ни одного по теме(((
Ответы не обязаны Вам нравиться. Будете еще фыркать, хохотать - перестану отвечать  Улыбающийся

Записан
Bepec
Гость
« Ответ #11 : Март 02, 2012, 15:07 »

2 потока, 2 буфера, 2 функции, 1 мьютекс...

А не отвечают по теме, ибо у вас вопрос невнятный.

Ваш код нужно не править - вам нужно новую программу написать. Так будет легче и проще.

PS ну чесслово я посмотрю на код и глаза расходятся Подмигивающий
Записан
lolbla2
Гость
« Ответ #12 : Март 02, 2012, 19:33 »

2 потока, 2 буфера, 2 функции, 1 мьютекс...

А не отвечают по теме, ибо у вас вопрос невнятный.

Ваш код нужно не править - вам нужно новую программу написать. Так будет легче и проще.

PS ну чесслово я посмотрю на код и глаза расходятся Подмигивающий

Ну да я тоже так и думал но когда начал реализовывать почему-то так просто не получается...

Изменил код вот так:
Код
C++ (Qt)
void Producer::run()
{
       qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
 
 
       while(true)
      {
 
//      bufferNotFull->wait(mutex);
       qDebug()<< this->currentThreadId();
     if(numUsedBytes == 0)
     {
        if(!messages.isEmpty())
       {
          mutex->lock();
          buffer[0] = messages.dequeue();
          qDebug() << buffer[0];
          numUsedBytes++;
          mutex->unlock();
       }
     }
//      bufferNotFull->wakeAll();
 
      }
}
 

и потребитель
Код
C++ (Qt)
void Consumer::run()
{
 
   while(true)
   {
 
//        bufferNotEmpty->wait(mutex);
        qDebug()<< this->currentThreadId();
       if(numUsedBytes != 0)
       {
           mutex->lock();
            sleep(2);
           qDebug() << buffer[0];
           numUsedBytes--;
           messages.enqueue(buffer[0]);
           mutex->unlock();
       }
//        emit SymbolReceived(buffer[0]);
 
//        bufferNotEmpty->wakeAll();
 
   }
 
}
 

ну и запускаю потоки кнопкой вот так:
Код
C++ (Qt)
void Widget::beginWork()
{
 
   producer->moveToThread(producer);
   consumer->moveToThread(consumer);
   producer->start();
   consumer->start();
//    producer->wait();
//    consumer->wait();
}
 
а другой кнопкой посылаю сигнал о том, чтобы производитель добавил новое сообщение:
Код
C++ (Qt)
void Widget::on_pushButton_2_clicked()
{
   emit newMessage();
} // Но почему-то сигнал не приходит до слота потока, и сообщение не добавляется вовсе
 

« Последнее редактирование: Март 02, 2012, 19:44 от lolbla2 » Записан
V1KT0P
Гость
« Ответ #13 : Март 02, 2012, 19:46 »

PS ну чесслово я посмотрю на код и глаза расходятся Подмигивающий
+1 Вот и хочется человеку помочь, а от одного взгляда на код все желание пропадает.
Ну да я тоже так и думал но когда начал реализовывать почему-то так просто не получается...
Сделай минимальный рабочий пример. Мне все-равно еще 3 часа делать нечего, а так может и помогу.
Записан
lolbla2
Гость
« Ответ #14 : Март 02, 2012, 19:50 »

PS ну чесслово я посмотрю на код и глаза расходятся Подмигивающий
+1 Вот и хочется человеку помочь, а от одного взгляда на код все желание пропадает.
Ну да я тоже так и думал но когда начал реализовывать почему-то так просто не получается...
Сделай минимальный рабочий пример. Мне все-равно еще 3 часа делать нечего, а так может и помогу.

ну вот предпоследний пост мой меньше кода вроде более разборчивый. Могу исходник прикрепить если так проще будет...
Записан
Страниц: [1] 2 3 ... 6   Вверх
  Печать  
 
Перейти в:  


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