1

I'm doing a pizzeria restaurant simulation, where the main thread is the Reception, it can take orders and transform it in abstract pizza object APizza, in this reception i have a kitchen object, which contain a list of cooks represented by threads (std::list< std::thread > _cooks) i want to pass theses abstract pizzas from the reception main thread, to my sub-threads cooks, and i want them to be able to pick from the ingredient stock (Stock *_ingredients) in the kitchen main threads, i know i must use mutex to lock ingredients stock variable before modifying it so many cooks won't access and change the data in the stock at the same time do unpredictable behavior.

I'm looking for some approach to passe theses pizzas and to make my main thread kitchen ingredient stock (Stock *_ingredients) stock accessible from the cooks.

Here's my architecture:


class Reception
{
    public:
        Reception(double, size_t, size_t);
        ~Reception();
        int Shell();
        APizza *MakeOrder(PizzaType, PizzaSize);
        void openKitchen();

    private:
        int parseCommands();
        std::map<size_t, pid_t> _kitchenList;

    protected:
        double _multiplier; //Cooking time multiplier.
        size_t _cooks; //Number of cook(s) per kitchen.
        size_t _restock; //Time in ms to restock ingredients.
};


class Kitchen
{
    public:
        Kitchen(double, size_t, size_t);
        ~Kitchen();
        APizza *MakeOrder(PizzaType, PizzaSize);
        void Status();
        void DispatchPizza(APizza *pizza);
        bool isFull();

    private:
        std::stack<APizza> \
            _pizzaWaiting;
        std::list<std::thread> _cooks;
        Stock *_ingredients;

        double _multiplier; //Cooking time multiplier.
        size_t _ncooks; //Number of cook(s) per kitchen.
        size_t _restock; //Time in ms to restock ingredients.
        size_t _ordersNow;
        //Pipe _pipe;
};

class Cook
{
    public:
        Cook(double _multiplier);
        ~Cook();
        void Run();
        bool canCook();
        void cookPizza(APizza *);

    private:
        APizza *_currPizza;
        bool _isCooking;
        double _multiplier;

};

Here is where i want to pass the pizza

int Reception::Shell()
  {
      std::string command;
      std::cout << "> ";
      std::list<std::string> orders;
      APizza *currPizza;
>>    Kitchen *kitch = new Kitchen(_multiplier, _cooks, _restock);

      while (1)
      {
          getline (std::cin, command);
          if (!command.compare("exit") || std::cin.eof())
              return(0);
          else
          {
              orders = splitStr(command, ';');
          }
          if (!orders.empty())
          {
              for (const std::string & order : orders)
              {
                  size_t nPizza = getPizzaNbr(order);
                  PizzaType tPizza = getPizzaType(order);
                  PizzaSize sPizza = getPizzaSize(order);
                  if (nPizza == 0 || tPizza == (PizzaType)0 || sPizza == (PizzaSize)0) {
                      std::cout << "wrong input: " << nPizza << " " << tPizza << " " << sPizza << std::endl;
                      continue;
                  }
                  std::cout << "good input: " << nPizza << " " << tPizza << " " << sPizza << std::endl;
                  for (size_t i = 0; i != nPizza; i++)
                  {   
                      currPizza = this->MakeOrder(tPizza, sPizza);
                      //
                      // SEND this currPizza to to kitchen cook's thread
                      //

                      std::cout << "Nouvelle pizza, type: " << currPizza->getType() \
                          << " size: " << currPizza->getSize() << std::endl;
                  }   
              }       
          }           
          std::cout << std::endl << "> ";
      }               
      return 0;       
  }
  • Looks like you have all the right pieces, so what have you tried? Note: Unlike many languages, in c++ you don't have to `new` all of the objects. [In fact it's best if you don't](https://stackoverflow.com/questions/6500313/why-should-c-programmers-minimize-use-of-new). `Kitchen kitch(_multiplier, _cooks, _restock);` looks like it should work here and be a lot less likely to blow-up in your face or leak. – user4581301 May 10 '20 at 15:54
  • Reading a bit more, the above comment about `kitchen` is good advice, but doesn't fit in with how the interface appears to use `Kitchens`. `void openKitchen();` and `std::map _kitchenList;` suggest that there should be multiple `Kitchen`s. Is this what you are really asking about? – user4581301 May 10 '20 at 15:58
  • @user4581301 thanks but dont worry about multiple kitchens, just one for now, please. and i haven't tried nothing i'ma bit lost right now, however i'm looking at std::atomic(i'm figuring what it does right now) and std::mutex to lock the stock before modyfing it is this good? – freeinternet May 10 '20 at 16:04
  • Use `std::mutex` because you need to protect entire transactions. For example, say you need to check that an ingredient is in stock and if it is, remove one instance. `std::atomic` would protect both of these operations separately, allowing thread B to slip in and remove the required item between Thread A's check that the item is in stock and Thread A removing the item. A `mutex` can protect both. – user4581301 May 10 '20 at 16:14
  • Recommendation: Get the logic worked out and tested with a simple example and build from that example. If you try to write code and then factor in threading you'll wind up discarding and rewriting a lot of your code after you find out it doesn't handle being threaded intelligently. – user4581301 May 10 '20 at 16:18
  • Recommendation: Make little helper methods like `get_ingredient` that does all of the mutex-locking and list management for getting an ingredient. Hide the nitty-gritty details as much as possible. It makes things easier to test and reduces the responsibility load on other methods. A method that needs an ingredient doesn't care how `Kitchen` gives it to them. It only cares that it got an ingredient (or didn't and calls for re-stocking). – user4581301 May 10 '20 at 16:27

1 Answers1

0

Honestly, just skipped through your code, there's a well-known trick in C++ in which you create a class that encapsulated pthread and passes the self pointer (this) to a new thread, I'll add some references, what I would generally recommend, create a general worker abstract class, whilst cook inherits from, the cook ctor gives it access to these abstract pizzas through the constructor or some setter function, here's an example:

class some_thread
{
public:
    some_thread_ctr(pizza_list * your_pizza_list) {};

    void start_thead()
    {
        pthread_create(&i, 0, somethread_main, this);
    }

    static void * somethread_main(void * somethread_ctx)
    {
        some_thread * ctx = (some_thread *) somethread_ctx;

        // Do actual thing
    }
    pthread_t i;
};


int main (void)
{
    pizza_list pz = new_pizza_list();

    some_thread first_cook(pz);
    some_thread second_cook(pz);

    first_cook.start_thead();
    second_cook.start_thead();
}

now this solves your problem as you can simply initialize an abstract pizza list from your main thread, give access to your cook-threads via shared memory (which would be passed on in your constructor) and just run them simultaneously, I must emphasize though that the function somethread_main which in this context represents the main of your cook thread, should be thread safe and it is up to you to access pizza_list in each thread safely with mutexes.

also, I've written the code without compiling it so it might now compile yet the concept itself should help you,

EDIT: as mentioned in the comments, you could definitely use std::thread instead of pthread_create, this is just a concept of passing this pointer to some function and using that function as a thread entry point thus allowing you to access its data members

DrPrItay
  • 726
  • 5
  • 18
  • This seems to answer a completely different set of questions and does with with an obsolete ideology. Use `std::thread`. – user4581301 May 10 '20 at 16:06
  • old trick, yet it works perfectly fine every time. one may call it obsolete yet it definitely solves his problems, and yes obviously you could use `std::thread` instead of `pthread` @user4581301 – DrPrItay May 10 '20 at 16:10