Using multithreading and share pointers [closed]
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
-3
down vote
favorite
I'm trying to find data racing in this code. I don't know why. Please, review it and let me know what can I change.
class Engine {
public:
Engine(const unsigned int &fuel_amount, const unsigned int &time_interval) :fuel_amount(fuel_amount),
time_interval(time_interval), disconnect(false)
std::thread thd( [this, fuel_amount, time_interval]
std::unique_lock<std::mutex> lk(m2);
while (!fuel_tanks.empty() && !disconnect)
return false;
);
~Engine()
std::lock_guard<std::mutex> lk(m2);
disconnect = true;
current_tank.notify_one();
if (thd.joinable()) thd.join();
void addTank(const std::shared_ptr<FuelTank> & fuel_tank)
std::lock_guard<std::mutex> lk(m2);
fuel_tanks.emplace_back(fuel_tank);
current_tank.notify_one();
//...
Here is Engine class which I use to take fuel in some time intervals using multithreading and share pointers. There also a FuelTank class, but helgrind found data racing in this class.
c++ multithreading
closed as off-topic by ÃÂìýÃÂñ á¿¥Ã栨Â, t3chb0t, Sam Onela, Incomputable, Toby Speight Jan 17 at 9:30
This question appears to be off-topic. The users who voted to close gave this specific reason:
- "Questions containing broken code or asking for advice about code not yet written are off-topic, as the code is not ready for review. After the question has been edited to contain working code, we will consider reopening it." â ÃÂìýÃÂñ á¿¥Ã栨Â, t3chb0t, Sam Onela, Incomputable, Toby Speight
add a comment |Â
up vote
-3
down vote
favorite
I'm trying to find data racing in this code. I don't know why. Please, review it and let me know what can I change.
class Engine {
public:
Engine(const unsigned int &fuel_amount, const unsigned int &time_interval) :fuel_amount(fuel_amount),
time_interval(time_interval), disconnect(false)
std::thread thd( [this, fuel_amount, time_interval]
std::unique_lock<std::mutex> lk(m2);
while (!fuel_tanks.empty() && !disconnect)
return false;
);
~Engine()
std::lock_guard<std::mutex> lk(m2);
disconnect = true;
current_tank.notify_one();
if (thd.joinable()) thd.join();
void addTank(const std::shared_ptr<FuelTank> & fuel_tank)
std::lock_guard<std::mutex> lk(m2);
fuel_tanks.emplace_back(fuel_tank);
current_tank.notify_one();
//...
Here is Engine class which I use to take fuel in some time intervals using multithreading and share pointers. There also a FuelTank class, but helgrind found data racing in this class.
c++ multithreading
closed as off-topic by ÃÂìýÃÂñ á¿¥Ã栨Â, t3chb0t, Sam Onela, Incomputable, Toby Speight Jan 17 at 9:30
This question appears to be off-topic. The users who voted to close gave this specific reason:
- "Questions containing broken code or asking for advice about code not yet written are off-topic, as the code is not ready for review. After the question has been edited to contain working code, we will consider reopening it." â ÃÂìýÃÂñ á¿¥Ã栨Â, t3chb0t, Sam Onela, Incomputable, Toby Speight
(Welcome to CR!) I think it easier to make head and tail of this question if the observation about helgrind (links welcome) was near the start. There's no disgrace in telling why pieces of code exist. (I'm trying to [do x, but] I don't know why.
reads funny (to me as a non-native speaker).)
â greybeard
Jan 16 at 20:19
add a comment |Â
up vote
-3
down vote
favorite
up vote
-3
down vote
favorite
I'm trying to find data racing in this code. I don't know why. Please, review it and let me know what can I change.
class Engine {
public:
Engine(const unsigned int &fuel_amount, const unsigned int &time_interval) :fuel_amount(fuel_amount),
time_interval(time_interval), disconnect(false)
std::thread thd( [this, fuel_amount, time_interval]
std::unique_lock<std::mutex> lk(m2);
while (!fuel_tanks.empty() && !disconnect)
return false;
);
~Engine()
std::lock_guard<std::mutex> lk(m2);
disconnect = true;
current_tank.notify_one();
if (thd.joinable()) thd.join();
void addTank(const std::shared_ptr<FuelTank> & fuel_tank)
std::lock_guard<std::mutex> lk(m2);
fuel_tanks.emplace_back(fuel_tank);
current_tank.notify_one();
//...
Here is Engine class which I use to take fuel in some time intervals using multithreading and share pointers. There also a FuelTank class, but helgrind found data racing in this class.
c++ multithreading
I'm trying to find data racing in this code. I don't know why. Please, review it and let me know what can I change.
class Engine {
public:
Engine(const unsigned int &fuel_amount, const unsigned int &time_interval) :fuel_amount(fuel_amount),
time_interval(time_interval), disconnect(false)
std::thread thd( [this, fuel_amount, time_interval]
std::unique_lock<std::mutex> lk(m2);
while (!fuel_tanks.empty() && !disconnect)
return false;
);
~Engine()
std::lock_guard<std::mutex> lk(m2);
disconnect = true;
current_tank.notify_one();
if (thd.joinable()) thd.join();
void addTank(const std::shared_ptr<FuelTank> & fuel_tank)
std::lock_guard<std::mutex> lk(m2);
fuel_tanks.emplace_back(fuel_tank);
current_tank.notify_one();
//...
Here is Engine class which I use to take fuel in some time intervals using multithreading and share pointers. There also a FuelTank class, but helgrind found data racing in this class.
c++ multithreading
edited Jan 16 at 20:07
Martin York
70.9k481244
70.9k481244
asked Jan 16 at 20:04
chriss
11
11
closed as off-topic by ÃÂìýÃÂñ á¿¥Ã栨Â, t3chb0t, Sam Onela, Incomputable, Toby Speight Jan 17 at 9:30
This question appears to be off-topic. The users who voted to close gave this specific reason:
- "Questions containing broken code or asking for advice about code not yet written are off-topic, as the code is not ready for review. After the question has been edited to contain working code, we will consider reopening it." â ÃÂìýÃÂñ á¿¥Ã栨Â, t3chb0t, Sam Onela, Incomputable, Toby Speight
closed as off-topic by ÃÂìýÃÂñ á¿¥Ã栨Â, t3chb0t, Sam Onela, Incomputable, Toby Speight Jan 17 at 9:30
This question appears to be off-topic. The users who voted to close gave this specific reason:
- "Questions containing broken code or asking for advice about code not yet written are off-topic, as the code is not ready for review. After the question has been edited to contain working code, we will consider reopening it." â ÃÂìýÃÂñ á¿¥Ã栨Â, t3chb0t, Sam Onela, Incomputable, Toby Speight
(Welcome to CR!) I think it easier to make head and tail of this question if the observation about helgrind (links welcome) was near the start. There's no disgrace in telling why pieces of code exist. (I'm trying to [do x, but] I don't know why.
reads funny (to me as a non-native speaker).)
â greybeard
Jan 16 at 20:19
add a comment |Â
(Welcome to CR!) I think it easier to make head and tail of this question if the observation about helgrind (links welcome) was near the start. There's no disgrace in telling why pieces of code exist. (I'm trying to [do x, but] I don't know why.
reads funny (to me as a non-native speaker).)
â greybeard
Jan 16 at 20:19
(Welcome to CR!) I think it easier to make head and tail of this question if the observation about helgrind (links welcome) was near the start. There's no disgrace in telling why pieces of code exist. (
I'm trying to [do x, but] I don't know why.
reads funny (to me as a non-native speaker).)â greybeard
Jan 16 at 20:19
(Welcome to CR!) I think it easier to make head and tail of this question if the observation about helgrind (links welcome) was near the start. There's no disgrace in telling why pieces of code exist. (
I'm trying to [do x, but] I don't know why.
reads funny (to me as a non-native speaker).)â greybeard
Jan 16 at 20:19
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
0
down vote
accepted
Bug
Well you have a bug in your code.
This is an automatic variable.
std::thread thd( [this, fuel_amount, time_interval] /* STUFF */ );
So it goes out of scope at the end of the constructor. Which means the destructor is called. Which means that std::terminate will be called if the thread has started. If the "thread of execution" has not started (ie it is not joinable) then it is just destroyed and no "thread of execution" was ever created.
So either this will cause the application to terminate or no thread will be created.
Code Review
Lets not place a huge function in the middle of the constructor. Lambdas' are nice but there best for one liners. If you have a whole complex function run then move that code into its own method and call it.
Don't use an if statement to return true/false. Just return the expression you are using for the test.
if (!fuel_tanks.empty()) return true;
return false;
// easier to read/write as
return !fuel_tanks.empty();
Its curious how you use completely different tests here:
current_tank.wait(lk, [this]
return !fuel_tanks.empty();
);
if (!fuel_tanks.empty() || !disconnect) {
So the conditional variable will never exit if disconnect
is set to true. So to cause the worker thread to exit you need to enter the destructor then add fuel.
I think you actuall need:
current_tank.wait(lk, [this]
// Exit if fuel tank is empty
// or the disconnect has been set to true.
return !fuel_tanks.empty() && !disconnect;
);
if (disconnect)
// If we disconnected we want the thread to exit.
// so force the exit with a return.
return;
// You only get here if there is fuel in the tank.
Your moving is not doing what you think
void addTank(const std::shared_ptr<FuelTank> & fuel_tank) // pass by const reference.
std::lock_guard<std::mutex> lk(m2);
fuel_tanks.emplace_back(fuel_tank); // this is creating a copy
// to pass as a parameter.
current_tank.notify_one();
What it should look like:
void addTank(std::shared_ptr<FuelTank>&& fuel_tank) // pass by r-value ref
std::lock_guard<std::mutex> lk(m2);
fuel_tanks.push_back(std::move(fuel_tank)); // still needs to be moved
// but you use push.
current_tank.notify_one();
Oh, Thank you so much. I don't know how can I skip this. Thank's a lot.
â chriss
Jan 16 at 20:18
1
Make the thread a member of the class.
â Martin York
Jan 16 at 20:22
@MartinYork, if the code is not working, I believe it would be better to guide them to C++ questions and answers chat room, so that CR would stay clean. I'm lurking around there usually, so it is not empty.
â Incomputable
Jan 17 at 9:44
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
0
down vote
accepted
Bug
Well you have a bug in your code.
This is an automatic variable.
std::thread thd( [this, fuel_amount, time_interval] /* STUFF */ );
So it goes out of scope at the end of the constructor. Which means the destructor is called. Which means that std::terminate will be called if the thread has started. If the "thread of execution" has not started (ie it is not joinable) then it is just destroyed and no "thread of execution" was ever created.
So either this will cause the application to terminate or no thread will be created.
Code Review
Lets not place a huge function in the middle of the constructor. Lambdas' are nice but there best for one liners. If you have a whole complex function run then move that code into its own method and call it.
Don't use an if statement to return true/false. Just return the expression you are using for the test.
if (!fuel_tanks.empty()) return true;
return false;
// easier to read/write as
return !fuel_tanks.empty();
Its curious how you use completely different tests here:
current_tank.wait(lk, [this]
return !fuel_tanks.empty();
);
if (!fuel_tanks.empty() || !disconnect) {
So the conditional variable will never exit if disconnect
is set to true. So to cause the worker thread to exit you need to enter the destructor then add fuel.
I think you actuall need:
current_tank.wait(lk, [this]
// Exit if fuel tank is empty
// or the disconnect has been set to true.
return !fuel_tanks.empty() && !disconnect;
);
if (disconnect)
// If we disconnected we want the thread to exit.
// so force the exit with a return.
return;
// You only get here if there is fuel in the tank.
Your moving is not doing what you think
void addTank(const std::shared_ptr<FuelTank> & fuel_tank) // pass by const reference.
std::lock_guard<std::mutex> lk(m2);
fuel_tanks.emplace_back(fuel_tank); // this is creating a copy
// to pass as a parameter.
current_tank.notify_one();
What it should look like:
void addTank(std::shared_ptr<FuelTank>&& fuel_tank) // pass by r-value ref
std::lock_guard<std::mutex> lk(m2);
fuel_tanks.push_back(std::move(fuel_tank)); // still needs to be moved
// but you use push.
current_tank.notify_one();
Oh, Thank you so much. I don't know how can I skip this. Thank's a lot.
â chriss
Jan 16 at 20:18
1
Make the thread a member of the class.
â Martin York
Jan 16 at 20:22
@MartinYork, if the code is not working, I believe it would be better to guide them to C++ questions and answers chat room, so that CR would stay clean. I'm lurking around there usually, so it is not empty.
â Incomputable
Jan 17 at 9:44
add a comment |Â
up vote
0
down vote
accepted
Bug
Well you have a bug in your code.
This is an automatic variable.
std::thread thd( [this, fuel_amount, time_interval] /* STUFF */ );
So it goes out of scope at the end of the constructor. Which means the destructor is called. Which means that std::terminate will be called if the thread has started. If the "thread of execution" has not started (ie it is not joinable) then it is just destroyed and no "thread of execution" was ever created.
So either this will cause the application to terminate or no thread will be created.
Code Review
Lets not place a huge function in the middle of the constructor. Lambdas' are nice but there best for one liners. If you have a whole complex function run then move that code into its own method and call it.
Don't use an if statement to return true/false. Just return the expression you are using for the test.
if (!fuel_tanks.empty()) return true;
return false;
// easier to read/write as
return !fuel_tanks.empty();
Its curious how you use completely different tests here:
current_tank.wait(lk, [this]
return !fuel_tanks.empty();
);
if (!fuel_tanks.empty() || !disconnect) {
So the conditional variable will never exit if disconnect
is set to true. So to cause the worker thread to exit you need to enter the destructor then add fuel.
I think you actuall need:
current_tank.wait(lk, [this]
// Exit if fuel tank is empty
// or the disconnect has been set to true.
return !fuel_tanks.empty() && !disconnect;
);
if (disconnect)
// If we disconnected we want the thread to exit.
// so force the exit with a return.
return;
// You only get here if there is fuel in the tank.
Your moving is not doing what you think
void addTank(const std::shared_ptr<FuelTank> & fuel_tank) // pass by const reference.
std::lock_guard<std::mutex> lk(m2);
fuel_tanks.emplace_back(fuel_tank); // this is creating a copy
// to pass as a parameter.
current_tank.notify_one();
What it should look like:
void addTank(std::shared_ptr<FuelTank>&& fuel_tank) // pass by r-value ref
std::lock_guard<std::mutex> lk(m2);
fuel_tanks.push_back(std::move(fuel_tank)); // still needs to be moved
// but you use push.
current_tank.notify_one();
Oh, Thank you so much. I don't know how can I skip this. Thank's a lot.
â chriss
Jan 16 at 20:18
1
Make the thread a member of the class.
â Martin York
Jan 16 at 20:22
@MartinYork, if the code is not working, I believe it would be better to guide them to C++ questions and answers chat room, so that CR would stay clean. I'm lurking around there usually, so it is not empty.
â Incomputable
Jan 17 at 9:44
add a comment |Â
up vote
0
down vote
accepted
up vote
0
down vote
accepted
Bug
Well you have a bug in your code.
This is an automatic variable.
std::thread thd( [this, fuel_amount, time_interval] /* STUFF */ );
So it goes out of scope at the end of the constructor. Which means the destructor is called. Which means that std::terminate will be called if the thread has started. If the "thread of execution" has not started (ie it is not joinable) then it is just destroyed and no "thread of execution" was ever created.
So either this will cause the application to terminate or no thread will be created.
Code Review
Lets not place a huge function in the middle of the constructor. Lambdas' are nice but there best for one liners. If you have a whole complex function run then move that code into its own method and call it.
Don't use an if statement to return true/false. Just return the expression you are using for the test.
if (!fuel_tanks.empty()) return true;
return false;
// easier to read/write as
return !fuel_tanks.empty();
Its curious how you use completely different tests here:
current_tank.wait(lk, [this]
return !fuel_tanks.empty();
);
if (!fuel_tanks.empty() || !disconnect) {
So the conditional variable will never exit if disconnect
is set to true. So to cause the worker thread to exit you need to enter the destructor then add fuel.
I think you actuall need:
current_tank.wait(lk, [this]
// Exit if fuel tank is empty
// or the disconnect has been set to true.
return !fuel_tanks.empty() && !disconnect;
);
if (disconnect)
// If we disconnected we want the thread to exit.
// so force the exit with a return.
return;
// You only get here if there is fuel in the tank.
Your moving is not doing what you think
void addTank(const std::shared_ptr<FuelTank> & fuel_tank) // pass by const reference.
std::lock_guard<std::mutex> lk(m2);
fuel_tanks.emplace_back(fuel_tank); // this is creating a copy
// to pass as a parameter.
current_tank.notify_one();
What it should look like:
void addTank(std::shared_ptr<FuelTank>&& fuel_tank) // pass by r-value ref
std::lock_guard<std::mutex> lk(m2);
fuel_tanks.push_back(std::move(fuel_tank)); // still needs to be moved
// but you use push.
current_tank.notify_one();
Bug
Well you have a bug in your code.
This is an automatic variable.
std::thread thd( [this, fuel_amount, time_interval] /* STUFF */ );
So it goes out of scope at the end of the constructor. Which means the destructor is called. Which means that std::terminate will be called if the thread has started. If the "thread of execution" has not started (ie it is not joinable) then it is just destroyed and no "thread of execution" was ever created.
So either this will cause the application to terminate or no thread will be created.
Code Review
Lets not place a huge function in the middle of the constructor. Lambdas' are nice but there best for one liners. If you have a whole complex function run then move that code into its own method and call it.
Don't use an if statement to return true/false. Just return the expression you are using for the test.
if (!fuel_tanks.empty()) return true;
return false;
// easier to read/write as
return !fuel_tanks.empty();
Its curious how you use completely different tests here:
current_tank.wait(lk, [this]
return !fuel_tanks.empty();
);
if (!fuel_tanks.empty() || !disconnect) {
So the conditional variable will never exit if disconnect
is set to true. So to cause the worker thread to exit you need to enter the destructor then add fuel.
I think you actuall need:
current_tank.wait(lk, [this]
// Exit if fuel tank is empty
// or the disconnect has been set to true.
return !fuel_tanks.empty() && !disconnect;
);
if (disconnect)
// If we disconnected we want the thread to exit.
// so force the exit with a return.
return;
// You only get here if there is fuel in the tank.
Your moving is not doing what you think
void addTank(const std::shared_ptr<FuelTank> & fuel_tank) // pass by const reference.
std::lock_guard<std::mutex> lk(m2);
fuel_tanks.emplace_back(fuel_tank); // this is creating a copy
// to pass as a parameter.
current_tank.notify_one();
What it should look like:
void addTank(std::shared_ptr<FuelTank>&& fuel_tank) // pass by r-value ref
std::lock_guard<std::mutex> lk(m2);
fuel_tanks.push_back(std::move(fuel_tank)); // still needs to be moved
// but you use push.
current_tank.notify_one();
edited Jan 16 at 20:22
answered Jan 16 at 20:12
Martin York
70.9k481244
70.9k481244
Oh, Thank you so much. I don't know how can I skip this. Thank's a lot.
â chriss
Jan 16 at 20:18
1
Make the thread a member of the class.
â Martin York
Jan 16 at 20:22
@MartinYork, if the code is not working, I believe it would be better to guide them to C++ questions and answers chat room, so that CR would stay clean. I'm lurking around there usually, so it is not empty.
â Incomputable
Jan 17 at 9:44
add a comment |Â
Oh, Thank you so much. I don't know how can I skip this. Thank's a lot.
â chriss
Jan 16 at 20:18
1
Make the thread a member of the class.
â Martin York
Jan 16 at 20:22
@MartinYork, if the code is not working, I believe it would be better to guide them to C++ questions and answers chat room, so that CR would stay clean. I'm lurking around there usually, so it is not empty.
â Incomputable
Jan 17 at 9:44
Oh, Thank you so much. I don't know how can I skip this. Thank's a lot.
â chriss
Jan 16 at 20:18
Oh, Thank you so much. I don't know how can I skip this. Thank's a lot.
â chriss
Jan 16 at 20:18
1
1
Make the thread a member of the class.
â Martin York
Jan 16 at 20:22
Make the thread a member of the class.
â Martin York
Jan 16 at 20:22
@MartinYork, if the code is not working, I believe it would be better to guide them to C++ questions and answers chat room, so that CR would stay clean. I'm lurking around there usually, so it is not empty.
â Incomputable
Jan 17 at 9:44
@MartinYork, if the code is not working, I believe it would be better to guide them to C++ questions and answers chat room, so that CR would stay clean. I'm lurking around there usually, so it is not empty.
â Incomputable
Jan 17 at 9:44
add a comment |Â
(Welcome to CR!) I think it easier to make head and tail of this question if the observation about helgrind (links welcome) was near the start. There's no disgrace in telling why pieces of code exist. (
I'm trying to [do x, but] I don't know why.
reads funny (to me as a non-native speaker).)â greybeard
Jan 16 at 20:19