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

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

Страниц: [1] 2 3 ... 5   Вниз
  Печать  
Автор Тема: Некорректное выполнение  (Прочитано 21348 раз)
Satansoft
Гость
« : Ноябрь 22, 2014, 17:29 »

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

С GUI немного разобрался, но вот логика... реализовывал её средствами С++11 т.к так яснее создание тредов. Приложение вызывает по нажатии на кнопку функции из класса MainWindow, результат выполнения метода Dinner_a выводит в QListWidget. Основной проблемой является доступ к методам внутри класса и пересылкам их возвращаемых значений в вызов. понятно, что вызов из кнопки - колханство, но как связать вызов из main с нажатием кнопки не ясно.

mainwindow.h
Код:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#define M 100
#include <ui_mainwindow.h>
#include <QMainWindow>
#include <QListWidget>
#include <thread>
#include <QThread>
#include <mutex>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);

        int Cooking_a()
        {
            int food=M;

            return food;
        }

        int Dinner_a(int food)
        {
            std::mutex eating;
            eating.lock();
            QThread::msleep(5000);
            ui->listWidget->addItem(QString::number(food) + " cannibal ate");
            food--;
            eating.unlock();

            return 0;
        }

            ~MainWindow();

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp
Код:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#define N 20
#define M 100

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    std::thread Cannibals[N];
    while(true)
    {
        std::thread cook = std::thread(&MainWindow::Cooking_a, this);
        cook.join();

        int food=Cooking_a();


        for(int i=0;i<food;i++)
                {
                   int coven = M;
                   Cannibals[i] = std::thread(&MainWindow::Dinner_a, this, coven);
                   coven --;
                   Cannibals[i].join();
                }

    }

}

void MainWindow::on_pushButton_2_clicked()
{
    exit(0);
}
Записан
Alexu007
Гость
« Ответ #1 : Ноябрь 23, 2014, 11:40 »

Чё то маловато кода для такой задачи...
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Ноябрь 23, 2014, 15:28 »

Отличная задачка, только сначала с логикой разберитесь, а потом UI рисуйте
Код:
        int Dinner_a(int food)
        {
            std::mutex eating;
            eating.lock();
            QThread::msleep(5000);
            ui->listWidget->addItem(QString::number(food) + " cannibal ate");
            food--;
            eating.unlock();

            return 0;
        }
1) Локальный мутекс ничего не защищает
2) Пока выходит что дите съело одну сливу и return 0. А должно есть пока папв (push_button) не скажет "хватит жрать"
3) Никто не говорил что пока один ест свою сливу - все должны ждать, поэтому msleep должен быть не под мутексом
4) UI не будет работать из др нитки (а только из главной), поэтому заряжайте сигнал

Потом дальше поговорим, пока слишком резво  Улыбающийся
Записан
vulko
Гость
« Ответ #3 : Ноябрь 23, 2014, 17:24 »

реализовывал её средствами С++11 т.к так яснее создание тредов

мож лучше qthread, не?))
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Ноябрь 24, 2014, 12:54 »

Здесь хорошо на семафорах, содержательная часть

Код
C++ (Qt)
bool doEat = true;
QAtomicInt numPlum(100);
QSemaphore childSemaphore(numPlum);
QSemaphore mamaSemaphore;
 
void ChildThread::run( void )
{
while (doEat) {
 childSemaphore.acquire();
 if (!doEat) break;
 if (!numPlum.deref())
  mamaSemaphore.release();
}
}
 
Но можно ли обойтись без атомарного счетчика (numPlum)? Мне кажется что нет
Записан
Alexu007
Гость
« Ответ #5 : Ноябрь 24, 2014, 21:01 »

Задача интересная. Я бы тож такую задачу попробовал решить. Только не знаю, с чего начать. Вот допустим, я сделал форму, на ней кнопку пуск. Пару меток - дети, которые кушают. То есть они сперва сытые (допустим 10), потом начинают хотеть кушать (сытость падает), и когда она становится равна 0 - берут сливу.  Пару - сперва два потока замутить, потом когда принцип будет понятен, увеличить можно.

И собственно тарелка int - на форме это метка с цифрой, сколько на ней слив. Сразу вопрос - где объявлять "тарелку"? Делать её глобальной, или где? К ней кроме детей ещё мама должна доступ иметь.

Дети очевидно класс и экземпляры класса. Они должны уметь "голодать", т.е. сами уменьшать свою сытость до 0. Как они могут голодать? В потоке ребёнка через паузу уменьшать соотв. число?  И отправлять сигнал к слоту тарелки?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #6 : Ноябрь 24, 2014, 21:26 »

А вы не начинайте с формы. Начните с участников действа.
У нас есть тарелка, у нас есть мама, у нас есть дети. Это три класса.
Мама должна уметь накладывать фрукты в тарелку, т.е. у тарелки должен быть метод для этого (мама знает про тарелку - хранит ссылку на объект тарелки).
Дети должны уметь брать фрукты, еще один метод (дети так же знают про тарелку + они знают про маму, что бы ее позвать).
Можно продумать вариант с "умной" тарелкой, которая зовет маму когда опустеет вместо детей. Улыбающийся
Голодание у детей можно сделать с помощью таймера, вышло время - ребенок проголодался - полез за фруктом - нет, позвал маму.

А вот когда это все заработает, можно подумать как это удобно показывать на форме.

Псевдокод функции main:
Код
C++ (Qt)
{
   QApplication app(...);
 
   // Создали тарелку, пока пустую
   Plate plate;
 
   // Маман
   Mom mom( plate );
 
   // Спиногрызы
   QList<Child> childs;
   for( int i = 0; i < MaxChilds; ++i )
       childs.append( Child( plate, mom, appetite( i ) ) );    // У каждого ребенка свой аппетит
 
   // Киданули им слив
   plate.putPlum( 100 );
 
   // Запустили симуляцию
   app.exec();
}
 

Объект мамы считает сколько оно всего положила слив, каждый ребенок считает сколько он съел. Всю статистику потом визуализируем.
« Последнее редактирование: Ноябрь 24, 2014, 21:53 от Old » Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #7 : Ноябрь 24, 2014, 22:03 »

Наверное самый примитивный вариант тарелки:

Код
C++ (Qt)
class Plate
{
public:
   explicite Plate() : m_plums( 0 ) {}
 
   // Положить слив
   void putPlums( unsigned int num )
   {
       QMutexLocker lock( &m_mutex );
       m_plums += num;
   }
 
   // Если в тарелке сливы есть, то берем одну и возвращаем true
   // Если тарелка пуста, возвращаем false (по этому признаку, ребенок может звать маму)
   bool takePlum()
   {
       QMutexLocker lock( &m_mutex );
       if( !m_plums )
           return false;
       --m_plums;
       return true;
   }
 
private:
   unsigned int m_plums;
   QMutex m_mutex;
};
 

Примерный алгоритм: дети, как проголодается, вызывают takePlum тарелки, как только эта функция начнет возвращать false, они начинаю звать маму, мама соответственно делает putPlums тарелке.
« Последнее редактирование: Ноябрь 24, 2014, 22:07 от Old » Записан
Alexu007
Гость
« Ответ #8 : Ноябрь 24, 2014, 22:36 »

А вы не начинайте с формы. Начните с участников действа.
У нас есть тарелка, у нас есть мама, у нас есть дети. Это три класса.
Мама должна уметь накладывать фрукты в тарелку, т.е. у тарелки должен быть метод для этого (мама знает про тарелку - хранит ссылку на объект тарелки).
Дети должны уметь брать фрукты, еще один метод (дети так же знают про тарелку + они знают про маму, что бы ее позвать).
Можно продумать вариант с "умной" тарелкой, которая зовет маму когда опустеет вместо детей. Улыбающийся
Голодание у детей можно сделать с помощью таймера, вышло время - ребенок проголодался - полез за фруктом - нет, позвал маму.

А вот когда это все заработает, можно подумать как это удобно показывать на форме.
Ну дети понятно. Их хоть много. Мама класс, ладно. Но тарелка? Это же просто переменная, в которую мама добавляет, а дети забирают. Её тоже оформлять как класс? Из одной переменной?
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #9 : Ноябрь 24, 2014, 22:39 »

Я бы оформил, точнее уже оформил чуть выше. Улыбающийся
Сейчас у нас в тарелке могут быть только сливы, а завтра там будут еще яблоки и персики с виноградом.
« Последнее редактирование: Ноябрь 24, 2014, 23:03 от Old » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Ноябрь 25, 2014, 10:30 »

Я бы оформил, точнее уже оформил чуть выше. Улыбающийся
Сейчас у нас в тарелке могут быть только сливы, а завтра там будут еще яблоки и персики с виноградом.
А пока только сливы - я бы не спешил с классом "тарелка".

Код
C++ (Qt)
   // Маман
   Mom mom( plate );
 
   // Спиногрызы
   QList<Child> childs;
   for( int i = 0; i < MaxChilds; ++i )
       childs.append( Child( plate, mom, appetite( i ) ) );    // У каждого ребенка свой аппетит
 
   // Киданули им слив
   plate.putPlum( 100 );
 
   // Запустили симуляцию
   app.exec();
}
 
Хмм... спорно. Если тарелка сама добавляет сливы - зачем тогда мама? И технически неясно что есть копирование класса Child. Я бы начинал по-другому, сначала распределил бы классы по ниткам

- каждый ребенок нитка
- мама еще 1 нитка

Ну и должен быть папа - пресловутый флажок по которому все завершается. Пусть это будет из главной нитки по нажатию на кнопку. Скелетик такой

Код
C++ (Qt)
   QApplication app(...);
 
   // Мама
   Mom mom();
 
   // Дети
   QVector <Child *> childs;
   for( int i = 0; i < MaxChilds; ++i )
       childs.append(new Child(...));
 
   // запускаем
   mom.start();  
   for( int i = 0; i < MaxChilds; ++i )
       childs[i]->start();
 
   // UI
   SetupUI();
   app.exec();
 
  // ждем пока все нитки выйдут
   mom.wait();  
   for( int i = 0; i < MaxChilds; ++i )
       childs[i]->wait();
 
  // печатаем статистику
  PrintStat();
 
  // удаляем отработавшие нитки
 qDeleteAll(childs.begin(), childs.end());
По поводу "зовет маму" - можно по-всякому

- если миска пуста. Тут может получиться что 2 и более детей зовут. Это не проблема, мама (захватив мутекс) может проверить

- зовет взявший последнюю сливу, это оптимальнее

2Alexu007 - главное в задаче не сказано, а подразумевается: нужно каким-то образом останавливать нитки (детей и маму) когда им нечего делать             
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #11 : Ноябрь 25, 2014, 11:22 »

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

Хмм... спорно. Если тарелка сама добавляет сливы - зачем тогда мама?
Нет, тарелка сама не добаляет, это должна делать мама (вызывать этот метод).
В main мы изначально наполняем тарелку сливами, что бы они уже там были. Этого можно не делать, тогда дети захотев взять сливу и обнаружив, что тарелка пуста - позовут маму и она ее наполнит, уже после начала симуляции.

И технически неясно что есть копирование класса Child.
Считайте что внутри Child используется Implicit Sharing, хотя это был просто псевдокод.

Я бы начинал по-другому, сначала распределил бы классы по ниткам
- каждый ребенок нитка
- мама еще 1 нитка
Это все в условии задачи.
« Последнее редактирование: Ноябрь 25, 2014, 11:27 от Old » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Ноябрь 25, 2014, 11:31 »

Нет, тарелка сама не добаляет, это должна делать мама (вызывать этот метод).
Дело в том что если Вы хотели делать на мутексах (конечно можно и так), то мутекс должна захватить мама (а не тарелка)
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4349



Просмотр профиля
« Ответ #13 : Ноябрь 25, 2014, 11:33 »

Дело в том что если Вы хотели делать на мутексах (конечно можно и так), то мутекс должна захватить мама (а не тарелка)
С чего бы это? Улыбающийся

И что значит захватывает мама или тарелка? Если мама вызывает метод тарелки putPlums, кто захватывает мьютекс? Улыбающийся

А делать можно еще много на чем, хоть на атомарных операциях.
« Последнее редактирование: Ноябрь 25, 2014, 11:37 от Old » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Ноябрь 25, 2014, 12:46 »

С чего бы это? Улыбающийся

И что значит захватывает мама или тарелка? Если мама вызывает метод тарелки putPlums, кто захватывает мьютекс? Улыбающийся
Покажите как "разбуженная мама" наполняет тарелку (и снова засыпает), я объясню что имею ввиду.
Записан
Страниц: [1] 2 3 ... 5   Вверх
  Печать  
 
Перейти в:  


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