Send abstract object from main thread to others thread [closed] - c++

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
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;
}

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

Related

Class that holds objects of another class within an std::array unexpectedly goes into constructor of the subclass within the array

We are tasked to create a class based Todo-List. I have created a Class called Task and another one called List. List has an std::array as a member which contains objects of type Task. List has a member function that creates a task and one that prints the entire list.
The problem I'm facing is that the std::array<Task,3> declaration automatically calls the constructor of Task 3 times and writes the tasks into the array. This is less of a problem when using an array and saves me the createTask() function which I no longer need to call, but if i want to use a Std::vector to hold a variable amount of tasks i always get an error "vector subscript out of range". Additionally I only want to add a task when I want to, not until whatever container type is full. How do I go about tackling this problem?
class Task
{
private:
std::array<std::string, 3> m_list;
std::string m_completed{ "no" };
public:
Task()
{
std::cout << "Enter Task Name: ";std::cin >> m_list[0]; //cant do white spaces yet
m_list[1] = "23.04.2021"; //needs way of getting current date
m_list[2] = m_completed;
system("CLS");
}
void printTask()const
{
std::cout << "Task Name: " << m_list[0] << " " << "created on: " << m_list[1] << " " << "completed?: " << m_list[2] << std::endl;
std::cout << "------------------------------------------------------------------------------------------------------------------------" << '\n';
}
};
class List{
private:
std::array<Task,3> listOfTasks; //this automatically calls the constructor 3 times and writes the objects into the array
int m_vectorsize{ 0 };
public:
List() {};
void createTask()
{
Task t1;
listOfTasks[m_vectorsize] = t1;
++m_vectorsize;
}
void printTasklist()
{
for (int count{ 0 }; count <3;count++)
{
listOfTasks[count].printTask();
}
}
};

print sum of data members of child classes in parent function [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
#include <iostream>
using namespace std;
class Fruit {
protected:
int nr_fruits = 0;
public:
void printTotal() {
cout << "Total fruits in the basket: " << nr_fruits << endl;
}
};
class Mango : public Fruit {
int nr_mangoes;
public:
void getMango(int x) {
nr_mangoes = x;
cout << "There are " << nr_mangoes << " mangoes in the basket" << endl;
nr_fruits = nr_fruits + nr_mangoes;
}
};
class Apple : public Fruit {
int nr_apples;
public:
void getApple(int x) {
nr_apples = x;
cout << "There are " << nr_apples << " apples in the basket" << endl;
nr_fruits = nr_fruits + nr_apples;
}
};
int main(int argc, const char * argv[]) {
Apple a1;
Mango m1;
a1.getApple(10);
a1.printTotal();
m1.getMango(20);
m1.printTotal();
return 0;
}
I need to make a function in the parent class Fruit, to be able to print the number of total fruits, in my case, nr_mangoes + nr_apples.
Obviously, the way i do it, the nr_fruits variable will output only the amount of mangoes or the amount of apples as the total amount of fruit.
How can i get to access the data members of the child classes, or make the variable nr_fruits so that it keeps the value throughout the program.
In this case you need the use of inheritance.
You will use virtual functions.
You will have to store in a vector of pointers to fruit, all the fruits you have.
vector<Fruit*> MyFruits;
Inside class Fruit you will implement a virtual function:
virtual int get_num_of_fruits(){}
And inside the child classes:
int get_num_of_fruits(){
return nr_child; //nr_apples,nr_mangos etc.
}
Then you will have an int nr_fruits = 0 and add to the number of all the fruits(apples,mangos etc.)
So, nr_fruits += MyFruits[i]->get_num_of_fruits(); for i = 0 to i<MyFruits.size()
In the case of your example and for simplicity, you can change your nr_fruits variable to be static, then initialize it after the class declaration:
class Fruit {
public:
static int nr_fruits;
void printTotal() {
cout << "Total fruits in the basket: " << nr_fruits << endl;
}
};
int Fruit::nr_fruits = 0;
However, without knowing the full scope of the requirements for your program, I think you may want to consider to design a better approach to your problem...

How can a class-based actor's state be accessed from a blocking context (C++ Actor Framework)

I'd like to access a class-based actor's state from a blocking context by exposing the current state via regular class methods. What's the best approach? I can think of three main avenues:
Class-based actors should not expose their state except by message passing (i.e. I'm doing something wrong to begin with)
The class method(s) should use a scoped_actor to send a message to the class-based actor and return the response.
The class method(s) should bypass the actor framework and simply access the member variable holding the state.
I attempted approach #2, but while I did figure out how to add the 'mutable' keyword to modify a captured variable, I was unable to successfully delay the method return until the captured variable could be set without creating deadlock.
Approach #3 seems to work for the example I've included below. Both guarded and unguarded access seemed to work, so I'm not sure if access to the state needs to be protected.
using size_atom = atom_constant<atom("size")>;
using done_atom = atom_constant<atom("done")>;
using a_type = typed_actor<
replies_to<int>::with<void>,
replies_to<size_atom>::with<size_t>,
replies_to<done_atom>::with<void>>;
class A : public a_type::base
{
public:
size_t size_direct_access()
{
return this->m_values.size();
}
size_t size_protected_access()
{
lock_guard<mutex> lock(this->m_mutex);
return this->m_values.size();
}
protected:
behavior_type make_behavior() override
{
return
{
[this](int value)
{
lock_guard<mutex> lock(this->m_mutex);
this->m_values.push_back(value);
},
[this](size_atom) -> size_t
{
lock_guard<mutex> lock(this->m_mutex);
return this->m_values.size();
},
[this](done_atom)
{
this->quit();
}
};
}
private:
vector<int> m_values;
mutex m_mutex;
};
void tester()
{
a_type testeeActor = spawn_typed<A, detached>();
abstract_actor* abstractActor = actor_cast<abstract_actor*, a_type>(testeeActor);
A* a = dynamic_cast<A*>(abstractActor);
scoped_actor self;
self->sync_send(testeeActor, 5).await(
[a, testeeActor, &self]()
{
size_t direct_access = a->size_direct_access();
size_t protected_access = a->size_protected_access();
aout(self) << "Direct: " << direct_access << " Protected: " << protected_access << endl;
self->sync_send(testeeActor, 3).await(
[a, testeeActor, &self]()
{
size_t direct_access = a->size_direct_access();
size_t protected_access = a->size_protected_access();
aout(self) << "Direct: " << direct_access << " Protected: " << protected_access << endl;
self->sync_send(testeeActor, 1).await(
[a, testeeActor, &self]()
{
size_t direct_access = a->size_direct_access();
size_t protected_access = a->size_protected_access();
aout(self) << "Direct: " << direct_access << " Protected: " << protected_access << endl;
self->sync_send(testeeActor, done_atom::value);
});
});
});
}
int main()
{
cout << "Spawning actors" << endl;
tester();
cout << "Awaiting all actors done" << endl;
await_all_actors_done();
cout << "Shutdown" << endl;
shutdown();
cout << "Press Enter to continue" << endl;
cin.get();
}
You're answering your own question right in the beginning:
Class-based actors should not expose their state except by message passing (i.e. I'm doing something wrong to begin with)
Actors communicate only via message passing. You should not try to violate this principle. Otherwise all safety guarantees provided by the runtime are gone. If you want shared, mutable state, the actor model is the wrong primitive for you.
That said, shared immutable state works fine in the actor model. You can pass a const-reference into the actor constructor to shared state with the outer scope, but then have to ensure that the reference remains valid for the lifetime of an actor. Another option would be to just use messages, which encapsulate the notion of shared, immutable data by providing a copy-on-write interface to its elements.
Upleveling: if you find yourself in need of accessing data from an actor, you should probably revisit the design of your program.

(C++ Beginner) How do I call these class functions into the main? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I keep having errors, I'm not sure how to call this Car class into the main function. The instructions I was given are below.
#include <iostream>
#include <string>
class Car{
public:
Car(){
int year = 1990;
std::string make = "Bentley";
int speed = 0;
};
Car(int new_year, std::string new_make, int new_speed) {
year = new_year;
make = new_make;
speed = new_speed;
}
int get_year() { return year; }
std::string get_make() { return make; }
int get_speed() { return speed; }
void accelerate() {
speed+=5;
}
void brake() {
speed-=5;
}
private:
int year;
std::string make;
int speed;
};
int main()
{
int year = 1990;
std::string make = "Bentley";
int speed = 0;
Car YourCar(year, make, speed);
std::cout << "Year: " << YourCar.get_year << std::endl;
std::cout << "Make: " << YourCar.get_make << std::endl;
std::cout << "Speed: " << YourCar.get_speed << std::endl;
}
Instructions:
Please implement a class named Car in C++ that has the following member
variables:
year. An int that holds the car’s model year.
make. A string object that holds the make of car.
speed. An int that holds the car’s current speed.
In addition, the class should have the following member functions:
Constructor. The constructor should accept the car’s year and make
as arguments and assign these values to the object’s year and make
member variables. The constructor should initialize the speed member
variable to 0.
Accessors or Getters. Appropriate accessors or getters should allow
values to be retrieved from an object’s year, make and speed member
variables.
accelerate. The accelerate function should add 5 to the speed member
variable each time it’s called.
brake. The brake function should subtract 5 from the speed member
variable each time it is called.
Demonstrate the class in a program that creates a Car object and then
calls the accelerate function 5 times. After each call to the accelerate function,
get the current speed of the car and display it. Then, call the brake
function 5 times. After each call to the break function, get the current speed
of car and display it.
Change
Car(){
int year = 1990;
std::string make = "Bentley";
int speed = 0;
};
to
Car(){
year = 1990;
make = "Bentley";
speed = 0;
}
You don't need to specify the data type here.
next,
std::cout << "Year: " << YourCar.get_year << std::endl;
std::cout << "Make: " << YourCar.get_make << std::endl;
std::cout << "Speed: " << YourCar.get_speed << std::endl;
Should be
std::cout << "Year: " << YourCar.get_year() << std::endl;
std::cout << "Make: " << YourCar.get_make() << std::endl;
std::cout << "Speed: " << YourCar.get_speed() << std::endl;
You forgot the () after the functions.

Am I creating my object arrays correctly? C++

I am trying to create a program that stores up to 50 players and the amount of wins they have. i.e. one use could be for for keeping track of sports teams and their amount of games won or something. However, I am having an issue when changing the player score. I am a beginner at C++, as you will probably be able to tell from my code. However, I have gone from knowing nothing whatsoever about coding to finishing three different tutorials and making a couple very simple command line programs in about a week. Any help as far as coding tips and how to make the scoreEdit() function work is thankfully accepted! Please find attached the players class, the scoreEdit() function, and my main function.
// for case 1. class that the scoreEdit() function uses!
class players
{
public:
void setName(string x)
{
name = x;
}
void addWin()
{
amtOfWins += 1;
}
void setWins(int x)
{
amtOfWins=x;
}
string getName()
{
return name;
}
int getWins()
{
return amtOfWins;
}
private:
string name;
int amtOfWins;
};
|
// for case 1. reads the file then stores each name in it's own player object and associates that with the amt of wins. Then rewrites all names and amtofwins to the file
void scoreEdit()
{
ifstream istats("stats.txt");
ofstream ostats("stats.txt");
if (istats.is_open() && ostats.is_open())
{
players player[50];
string tempName;
int tempWins;
while (istats >> tempName >> tempWins)
{
// reads in the name and amt of wins, and stores them in player object variables.
for (int x=0; x<50; x++)
{
player[x].setName(tempName);
player[x].setWins(tempWins);
}
}
string winner;
cout << "Who won?" << endl;
cin >> winner;
for (int x=0; x<50; x++)
{
if (player[x].getName()==winner)
{
player[x].addWin();
cout << "Ok. " << player[x].getName() << " has gained 1 point." << endl;
}
}
int x=0;
while (ostats << player[x].getName() << ' ' << player[x].getWins())
{
x++;
}
}
else
{
cout << "Quitting program. Stats could not be opened." << endl;
}
}
|
// main function
int main()
{
int x=0;
cout << "\n";
while (x==0) // not really sure if this is needed. Loops until case 4 or 5. Probably didn't need to use x. Oh well.
{
switch (choices())
{
case 0: // clears file
{
string decision;
cout << "ARE YOU SURE? This will wipe all data. (Type yes or no)\n" << endl;
cin >> decision;
if (decision=="yes")
{
clearStats();
cout << "STATS ARE WIPED.\n" << endl;
break;
}
else if (decision=="no")
{
cout << "Ok, stats will not be wiped.\n" << endl;
break;
}
else
{
cout << "Your input was not recognized. Stats will not be wiped.\n" << endl;
break;
}
}
case 1: // they want to add 1 to a player's score
{
scoreEdit();
break;
}
case 2: // they want to add a player
{
string name;
cout << "What is their name?" << endl;
cin >> name;
addPlayer(name);
break;
}
case 3: // they want to view the stats
{
readStats();
break;
}
case 4: // they want to quit. Simple! :)
{
return 0;
}
default: // means they did not input 1 2 3 or 4
{
cout << "Invalid input. Quitting program. Try again." << endl;
return 1;
}
}
}
}
EDIT: P.S. all my other functions/cases work. I just can't seem to find the problem with this one! Do I need to use a vector?
EDIT 2: Thanks for all the advice. Now, is there a way to check if the file still has data left to input? Right now, it inputs the lines just so that there are 50 player objects no matter what. Can I make a variable like int linesLeftInFile and use for (int x=0; x<linesLefInFile; x++)? Sorry for all the beginner questions.
You are trying to open the file twice, once for reading, once for writing, but in the same time.
...
ifstream istats("stats.txt");
ofstream ostats("stats.txt");
if (istats.is_open() && ostats.is_open())
...
When you open it for writing, like you do, the file content gets erased. The attempt to read the file will then fail, hence the big mess.
Open your stream first only to read, then close the stream, then open for write and put the results. Alternatively, you could consider an fstream with read and write.
By the way, it would be good practice for your players class to foresee a default constructor.
There are essentially two aspects:
A)
Am I creating my object arrays correctly? C++
which is related to persistence implementation and instance life-cycle issues, and
B)
EDIT: [...] Do I need to use a vector?
[...]
Right now, it inputs the lines just so that there are 50 player objects no matter what.
which is related to allocation and containers.
Both aspects of course intersect, e.g. a container like std::vector has much influence on the life-cycle of the instances it hosts.
Both aspects however have little to do with the functionality that is presented to the controller of the application, which is yet realized by the loop in main().
Thus, dealing with those aspects should be delegated to a class that separates them from the rest of the application.
Let's call that class-to-be PlayerDataBase.
PlayerDataBase will hold a container. But which?
Comlile-time fixed size arrays like
Player c_arra_players[50];
// or
std::array<Player,50> std_array_players;
are out of ansatz anyway; there is an external datum of arbitrary entity count which governs the multiplicity; thus the container must support run-time re-sizing.
A std::vector<Player> is plain and simple to use, but there's a seach to be performed
for (int x=0; x<50; x++) {
if (player[x].getName()==winner)
{
player[x].addWin();
cout << "Ok. " << player[x].getName() << " has gained 1 point." << endl;
}
}
which would have O(n) complexity on a sequential container like std::vector, whereas the same search on an associative like std::map (with the names used as keys) would be of O(log(n)) and about O(1) if std::unordered_map` would be used along with a perfect hash function.
On the other hand, adding and especially renaming players (use case: fixing typo in a nick) would be become more expensive for associative than sequential containers.
Especially for C++ learners it may be interesting to play a little with different internal storage representations, thus PlayerDataBase could be a template with a container template parameter.
There should only be one PlayerDataBase instance in the application and the controller should have a single point of access to that instance; thus it is meant to be a singleton.
The ifstream/ofstream/fstream issues can be dealt with quiet simple by PlayerDataBase - it's (private) ctor reads, or creates and reads, a stats file from an ifstream which is closed after the ctor completed.
Persisting the data is done by a flush() function, which opens an ofstream by using the _file_name member, writes, and that stream is closed on flush terminating.
///
///#brief modified singleton pattern
///
template<template<typename...> class Cont>
class PlayerDataBase : private players_container_adaptor<Cont> {
private:
using Traits = players_container_traits<Cont>;
public: // type interface
using container_type = typename Traits::players_container_type;
using Base = players_container_adaptor<Cont>;
struct no_such_player : public std::runtime_error {
no_such_player(const std::string& msg) : std::runtime_error(msg) {}
};
public: // creation interface
static PlayerDataBase& instance(const std::string& file_name = ::FILE_NAME)
throw (std::runtime_error) {
// automatically dtored
static PlayerDataBase _instance_(file_name); // throws
return _instance_;
}
public: // behaviour interface
void flush () const throw(std::ios::failure);
void addWin(const std::string& key) throw (no_such_player);
private: // types and function name resolution
using Adaptor = Base;
using Adaptor::getPlayer; // throws std::runtime_error
// container specific lookup,
using Adaptor::make_inserter; // std::copy(..,..,,make_inserter(Cont & c));
using Adaptor::emplace; // dispatches to container_specific emplace
using _asset_type = typename Traits::asset_type;
constexpr static auto BAD_AND_FAIL = std::ios::badbit | std::ios::failbit;
constexpr static auto BAD_ONLY = std::ios::badbit;
struct no_stats_file : public std::runtime_error {
no_stats_file(const std::string& msg) : std::runtime_error(msg) {}
};
private: // lifecycle interface
PlayerDataBase(const std::string&) throw (std::runtime_error);
~PlayerDataBase() noexcept;
// This is a singleton
PlayerDataBase(const PlayerDataBase&) = delete;
PlayerDataBase(PlayerDataBase&&) = delete;
PlayerDataBase& operator=(PlayerDataBase&&) = delete;
PlayerDataBase& operator=(const PlayerDataBase&) = delete;
PlayerDataBase& operator=(PlayerDataBase&) = delete;
private: // helpers
void create_data_file() const throw(std::ios::failure);
private: // state
container_type _players;
std::string _file_name;
}; // class PlayerDataBase
#include "playerdatabase.inl"
The required traits and adaptor templates could look like this:
template<template<typename...> class C> struct players_container_traits {};
// [...]
template<> struct players_container_traits<std::map> {
using players_container_type = std::map<std::string, Player>;
using player_ckv_type = players_container_type::value_type;
using player_kv_type = std::pair<std::string, Player>;
using asset_type = player_kv_type;
}; // struct player_container_traits<std::map>
// [...]
template<template<typename...> class C> struct players_container_adaptor{};
// [...]
template<> struct players_container_adaptor<std::map> {
using Traits = players_container_traits<std::map>;
using players_map_type = Traits::players_container_type;
static void post_ctor(players_map_type&) {
/* nop */
}
static Player& getPlayer(players_map_type& m, const std::string& key)
throw (std::runtime_error) {
auto it = m.find(key);
if (it == m.end())
throw std::runtime_error(key + " unknown");
return it->second;
} // addWin(players_map_t&,...)
static auto make_inserter(players_map_type& m)
-> decltype(std::inserter(m, m.begin())) {
return std::inserter(m, m.begin());
}
template<typename... Targs, typename K, typename... Args>
static void emplace(std::map<Targs...>& m, K&& k, Args&&... args) {
K _k = k;
m.emplace(std::piecewise_construct,
std::forward_as_tuple(_k),
std::forward_as_tuple(k, args...));
}
}; // template<> struct players_container_adaptor<std::map>
I postulated that the business class would be renamed to Player and gets a bunch of (noexcept) ctors and some related custom operators for << >>' forostreamresp.istream` output.
Happy hacking!
Addendum Jul 20th 2014
I don't see much reason for random sequence access anyway, thus if a sequential container would nevertheless be used (what I would not advocate due to the find complexity) then std::list would be more appropriate; that saves costs for possible complete, and expensive, re-allocations std::vector suffers from.