I want to use boost::asio (or asio stand alone) to query multiple network devices once a minute for data via asynchronous sockets. For a test I have already implemented a Client class and a console program that does that for one device (without repetition). Something like this:
class MyClient
{
public:
MyClient(asio::io_service& io_service);
void GetData(CompletionHandler completionHandler);
};
The MyClient::GetData class uses several asynchronous operations internally where the completion of each operation triggers the next until the data are available:
- Connect
- Read header
- Read data
- Disconnect
The console program that uses this class works like this:
int main(...)
{
asio::io_service io_service_;
MyClient c(io_service_, ...);
...
c.GetData([](std::error_code ec, const FloatVector& values){
//do something with values
});
io_service_.run();
...
}
Now I want to use the MyClient class in a GUI program for connecting to >10 devices once a minute but I'm stuck on the overall design.
First I created a thread pool where each thread executes io_service::run() of a single io_service instance.
Now whenever my program wants to read data from the devices it would have a loop over all devices and would have to create an instance of MyClient for each and call the GetData() method.
How does that work together with the io_service now that io_service::run() is executed in the threads of a pool? Can I simply call MyClient::GetData() in the GUI thread because it uses asynchronous operations internally or do I have to call something like io_service::post() ?
Update: My code and console demo follows roughly this example: www.boost.org/doc/libs/1_36_0/doc/html/boost_asio/example/http/client/async_client.cpp
But in a GUI program I don't want to run io_service.run() in the GUI thread. Now assume I have at least one extra thread that executes io_service.run() and a user presses a button that should start the device reading. The final completion handler should store the data in a database and update a graphical display to the user.
Maybe the button handler can simply instantiate MyClient and call GetData() on it and everything works as it should since MyClient knows the io_service and uses it f.e. in async_connect etc.
Does it work like this or am I mistaken here?
Note: at this point my question is not how to handle the data in the completion handler! It is how to correctly get the data in a multithreaded GUI program.