I have 2 threads,
one thread creates a pipeline and responsible for it,
another thread creates a communication of that pipeline with outer world,
so I want to create the communication after the pipeline is initialized.
This code works, but:
C26110 Caller failing to hold lock 'm' before calling function 'std::_Mutex_base::unlock'
, what is it about?
#include <iostream>
#include <mutex>
using namespace std::chrono_literals;
class Pipeline {
public:
Pipeline() { std::cout << "Pipeline()\n"; };
void init() { std::cout << "Pipeline::init()\n"; std::this_thread::sleep_for(3s); };
void run() { while (true) { std::cout << "Pipeline::run()\n"; std::this_thread::sleep_for(1s); } };
};
class Connection {
public:
Connection(Pipeline* p) { std::cout << "Connection()\n"; };
void run() { while (true) { std::cout << "Connection::run()\n"; std::this_thread::sleep_for(1s); } };
};
void pipeline_func(Pipeline** pipeline, std::mutex& m) {
*pipeline = new Pipeline();
(*pipeline)->init();
m.unlock();
(*pipeline)->run(); // run indefinitely
};
void connection_func(Pipeline** pipeline, std::mutex& m) {
m.lock();
Connection connection(*pipeline);
connection.run(); // run indefinitely
};
int main() {
Pipeline* pipeline = nullptr;
std::mutex m;
m.lock(); // lock there for stopping connection3_thread, intil mutex is unlocked in pipeline_thread
std::thread pipelineTh(pipeline_func, &pipeline, std::ref(m));
std::thread connectionTh(connection_func, &pipeline, std::ref(m));
pipelineTh.join();
connectionTh.join();
m.unlock();
}
Your current code is relying on undefined behavior by calling unlock()
in a thread that doesn't have ownership.
From mutex::unlock
:
The mutex must be locked by the current thread of execution, otherwise, the behavior is undefined.
You can simplify the code by initializing the pipeline before launching the threads. Then you don't need a mutex at all. If initialization takes a long time, you could do it in a thread, and launch the two threads in that thread.
#include <iostream>
#include <memory>
#include <thread>
using namespace std::chrono_literals;
class Pipeline {
public:
Pipeline() { std::cout << "Pipeline()\n"; };
void init() { std::cout << "Pipeline::init()\n"; std::this_thread::sleep_for(3s); };
void run() { while (true) { std::cout << "Pipeline::run()\n"; std::this_thread::sleep_for(1s); } };
};
class Connection {
public:
Connection(Pipeline* p) { std::cout << "Connection()\n"; };
void run() { while (true) { std::cout << "Connection::run()\n"; std::this_thread::sleep_for(1s); } };
};
void pipeline_func(std::shared_ptr<Pipeline> pipeline) {
pipeline->run(); // run indefinitely
};
void connection_func(std::shared_ptr<Pipeline> pipeline) {
Connection connection(pipeline.get());
connection.run(); // run indefinitely
};
int main() {
auto pipeline = std::make_shared<Pipeline>();
pipeline->init();
std::thread pipelineTh(pipeline_func, pipeline);
std::thread connectionTh(connection_func, pipeline);
pipelineTh.join();
connectionTh.join();
}