I am trying to make a program that uses shared resources, but all I get in the is std::logic_error. I think I am not using the mutex in the right way. Here is a snippet of the code.
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
struct camera {
std::string name;
std::string mac;
bool accessStatus;
};
class service {
public:
service(){};
void run();
private:
mutable std::mutex _mutex;
};
void service::run()
{
unsigned char option;
// some dummy camera object
camera camera_object;
camera_object.name = "camera_name";
camera_object.mac = "B6:24:3D:4C:00:9B";
camera_object.accessStatus = true;
// a vector of objects
std::vector<camera> cameras;
cameras.push_back(camera_object);
std::thread TT([&](){
while (true) {
// dummy condition
if (1 == 1) {
std::cout << cameras.size();
}
{
std::unique_lock<std::mutex> mlock(_mutex);
std::cout << "Choose an option:\n"
<< "\t 1. add one more camera \n"
<< "\t 2. get the theme \n"
<< std::flush;
option = getchar();
switch (option) {
case '1':
cameras.push_back(camera_object);
break;
case '2':
std::cout << "Not yet implemented\n" << std::flush;
break;
default:
std::cout << "Invalid input\n" << std::flush;
break;
}
}
// don't waste CPU resources
using namespace std::chrono_literals;
std::this_thread::sleep_for(1s);
system("clear");
}
});
TT.detach();
}
int main() {
service sv;
sv.run();
return 0;
}
Sometimes when I run it it just returns segmentation fault, but other times it let me choose an option, but after I choose it I get std::logic_error. I am trying to understand how mutex and multithreading works, but I have a hard time on this one.
Edit: the shared resource is the cameras vector. I am doing this program just to learn, it does not have a real objective. The condition 1==1 is there just to be sure that is always prints the vector size.
CodePudding user response:
Your problem isn't really the threading, it's the fact that your lambda captures by reference a cameras
vector that goes out of scope and is destroyed. You can reproduce this deterministically even with a single thread:
std::function<void(void)> foo()
{
std::vector<int> out_of_scope;
return [&]() { out_of_scope.push_back(42); };
}
anywhere you call the returned std::function
will have Undefined Behaviour, because the vector no longer exists. Invoking this UB in a different thread doesn't change anything.
If you're going to have shared state, you have to make sure it lives at least as long as the threads using it. Just make the cameras
vector a member of service
alongside the mutex that protects it. Or join the thread so the vector doesn't go out of scope until after the thread exits. Either will work.