0

I am solving a task on "producer and consumer" multithreading model. In consumer class I am trying to make a method that would get private buffer from producer object using "friend", but somewhy the code doesn't compile: 'units' is a private member of'p_c_model::Producer'. Spent a lot of time trying to fix it, but didn't succeed. Even signed up here. Please, help me fix this. Thank you in advance!

//Buffer.h
#ifndef TASK03_196_TATARINOV_23_BUFFER_H
#define TASK03_196_TATARINOV_23_BUFFER_H
#include <stack>
#include <mutex>
#include <condition_variable>
///Представляет модель "производитель и потребитель".
namespace p_c_model {
    ///Представляет собой класс для обмена данными между
    ///производителями и потребителями.
    template<class T>
    class Buffer {
    private:
        ///Максимальное количество элементов в буфере.
        static const size_t st_max_size = 10000;
        ///Контейнер для хранения элементов буфера.
        std::stack<T> st;
        std::mutex mu;
        std::condition_variable cond;
    public:
        ///Добавляет новый элемент в буфер.
        void add(const T& newElement);

        ///Удалаяет верхний элемент из буфера.
        T remove();

        ///Возвращает true, если буфер пуст.
        bool empty();
    };
}
#endif //TASK03_196_TATARINOV_23_BUFFER_H
//Buffer.cpp
#include "Buffer.h"
namespace p_c_model{
    template<class T>
    void Buffer<T>::add(const T& newElement) {
        while (true) {
            std::unique_lock<std::mutex> locker(mu);
            cond.wait(locker, [this](){ return st.size() < st_max_size; });
            st.push(newElement);
            locker.unlock();
            cond.notify_all();
            return;
        }
    }
    template<class T>
    T Buffer<T>::remove(){
        while (true)
        {
            std::unique_lock<std::mutex> locker(mu);
            cond.wait(locker, [this](){ return !st.empty(); });
            T  top = st.top();
            st.pop();
            locker.unlock();
            cond.notify_all();
            return top;
        }
    }
    template<class T>
    bool Buffer<T>::empty(){
        return st.empty();
    }
}
//Producer.h
#ifndef TASK03_196_TATARINOV_23_PRODUCER_H
#define TASK03_196_TATARINOV_23_PRODUCER_H
#include <fstream>
#include "Buffer.h"
#include "Consumer.h"
namespace p_c_model{
    class Producer{
    private:
        Buffer<std::string> units;
        Buffer<unsigned int> prices;
        std::ifstream fin;
        std::mutex mu;
        friend template class<T>
        void Consumer<T>::get_buffer(Producer& pr);
    public:
        explicit Producer(const std::string& path);
        ~Producer();

        void run();
    };
}
#endif //TASK03_196_TATARINOV_23_PRODUCER_H
//Producer.cpp
#include <iostream>
#include <thread>
#include "Producer.h"
namespace p_c_model{
    Producer::Producer(const std::string& path){
        fin.open(path);
    }
    Producer::~Producer() {
        fin.close();
    }
    void Producer::run() {
        std::string unit;
        unsigned int price;
        while(!fin.eof()){
            fin >> unit >> price;
            units.add(unit);
            prices.add(price);
            {
                std::unique_lock<std::mutex> locker(mu);
                std::cout << "Unit \"" << unit << "\" of price " << price <<
                          "is taken out of the warehouse\n";
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(50));
        }
    }
}
//Consumer.h
#ifndef TASK03_196_TATARINOV_23_CONSUMER_H
#define TASK03_196_TATARINOV_23_CONSUMER_H
#include <fstream>
#include "Buffer.h"
#include "Producer.h"
namespace p_c_model{
    class Producer;
    template<class T>
    class Consumer{
    private:
        Buffer<T>& objects;
        std::ofstream fout;
        std::mutex mu;
        unsigned long long overall_price;
    public:
        explicit Consumer(const std::string& path);
        ~Consumer();

        void run();

        void get_buffer(Producer& pr);
    };
}
#endif //TASK03_196_TATARINOV_23_CONSUMER_H
//Consumer.cpp
#include <iostream>
#include <thread>
#include "Producer.h"
#include "Consumer.h"
namespace p_c_model{
    template<class T>
    Consumer<T>::Consumer(const std::string& path) : overall_price(0){
        fout.open(path);
    }
    template<class T>
    Consumer<T>::~Consumer() {
        fout.close();
        std::cout << "Overall price is " << overall_price;
        fout << "Overall price is " << overall_price;
    }
    template<class T>
    void Consumer<T>::run() {
        if(typeid(T) == typeid(std::string)) {
            while (!objects.empty()) {
                T unit = objects.remove();
                fout << unit;
                {
                    std::unique_lock<std::mutex> locker(mu);
                    std::cout << "Unit \"" << unit << "\" is entrained in the truck\n";
                }
                std::this_thread::sleep_for(std::chrono::milliseconds(50));
            }
        } else if (typeid(T) == typeid(unsigned int)){
            while (!objects.empty()) {
                T unit = objects.remove();
                fout << unit;
                overall_price += *reinterpret_cast<unsigned long long *>(&unit);
                {
                    std::unique_lock<std::mutex> locker(mu);
                    std::cout << "+" << unit << " in price list\n";
                }
                std::this_thread::sleep_for(std::chrono::milliseconds(50));
            }
        }
    }
    template<class T>
    void Consumer<T>::get_buffer(Producer &pr) {
        if(typeid(T) == typeid(std::string)){
            objects = pr.units;
        } else if (typeid(T) == typeid(unsigned int)){
            objects = pr.prices;
        }
    }
}
  • 2
    Doesn't compile implies there's an error message somewhere. Very useful thing to add to questions about compiler errors, the message is. – user4581301 Nov 16 '20 at 17:43
  • 1
    [Why can templates only be implemented in the header file?](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) is worth your time to read. – user4581301 Nov 16 '20 at 17:45
  • I have already read this article today @user4581301 – nicolas_oleary Nov 16 '20 at 17:50
  • Not a compiler error, but [you may trip over Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-i-e-while-stream-eof-cons) later. Replace `while(!fin.eof()){ fin >> unit >> price;` with `while(!fin >> unit >> price){` – user4581301 Nov 16 '20 at 17:54
  • Are you asking about `friend template class`? – user4581301 Nov 16 '20 at 17:59
  • @user4581301 Got it about eof, thanks – nicolas_oleary Nov 16 '20 at 17:59
  • I think you're looking for `template friend void Consumer::get_buffer(Producer& pr);` – user4581301 Nov 16 '20 at 18:06
  • Oh, dear. I accidentally used "class" instead of "" and spent several hours trying to find the mistake. Thank you a lot! – nicolas_oleary Nov 16 '20 at 18:13
  • please post a [mcve] (I am certain you can reduce the code if the question is merely about accessing a member from a different class) and include the compiler error in the question – 463035818_is_not_a_number Nov 16 '20 at 18:49
  • As a new user you should read [How-to-ask?](https://stackoverflow.com/help/how-to-ask) and take the [tour]. – 463035818_is_not_a_number Nov 16 '20 at 18:50
  • if the problem was just a typo, you can consider to delete the question. Questions caused by a typo are not of great use for future readers and typically get closed – 463035818_is_not_a_number Nov 16 '20 at 18:51

0 Answers0