Basically there are a couple operational modes that my program can be in, each of them requiring initialization then updating. Each mode has its own configuration struct.
How can I after receiving a message and determining what mode its describing notify the main thread to initialize then start updating that mode? (I'm looking for an outline of the best way to do it in C 17)
To clarify, it is a daemon application. After initialization, the main thread's only job is to do the calculations required by mode updates. The networking is done on a separate worker thread with Boost.Asio. I also expect (as I am writing the client side program as well) that the frequency of mode changes will be low (~10hz max), so I want to avoid the use of a queue since the modes are for controlling the behavior of a robot, and a queue would add latency.
CodePudding user response:
Assuming your main thread can just sit and wait for the network download to complete before it starts the main code, you can use a std::condition_variable
Your main thread does this:
std::condition_variable cv;
std::mutex mut;
bool networkOperationCompleted;
Config globalconfig;
int main()
{
// initialize whatever kicks off the network thread
std::unique_lock<std::mutex> lck(mut);
while (networkOperationCompleted == false)
{
cv.wait();
}
}
meanwhile, your network thread does this:
extern std::condition_variable cv;
extern std::mutex mut;
extern bool networkOperationCompleted;
extern Config globalconfig;
void background_task()
{
Config config;
DownloadTheConfig(&config);
{
std::unique_lock<std::mutex> lck(m);
globalConfig = config;
networkOperationComplete = true;
cv.notify_all();
}
}
CodePudding user response:
I ended up going with something like this:
class config
{
public:
using empty = std::monostate;
struct modeA
{
...
};
struct modeB
{
...
};
template<typename T, typename Lambda>
void handle(Lambda&& handler) const
{
if (std::holds_alternative<T>(storage))
{
handler(std::get<T>(storage));
}
}
void clear()
{
storage = empty{};
}
private:
std::variant<empty, modeA, modeB> storage;
};
config server::pop_cfg()
{
std::unique_lock lock{cfg_mutex};
config copy{cfg};
cfg.clear();
return copy;
}
int main()
{
...
mode* mode;
while (true)
{
config cfg = server.pop_cfg();
cfg.handle<config::empty>([&](...) {
mode->update();
});
cfg.handle<config::modeA>([&](config::modeA cfg) {
mode = new ModeA(cfg);
});
cfg.handle<config::modeB>([&](config::modeB cfg) {
mode = new ModeB(cfg);
});
}
}