I am trying to create a thread to listen for UDP responses in c++ using the Boost ASIO library, this is my definition for the receive thread in my class file:
tello::tello(boost::asio::io_service& io_service, boost::asio::ip::udp::socket& socket, const boost::asio::ip::udp::endpoint& remote_endpoint)
: ip(remote_endpoint.address().to_string()),
port(remote_endpoint.port()),
io_service(io_service),
socket(socket),
remote_endpoint(remote_endpoint)
{
}
void tello::ReceiveThread() {
while (isListening_) {
try {
char receivedData[1024];
boost::system::error_code error;
size_t len = socket.receive_from(boost::asio::buffer(receivedData), remote_endpoint, 0, error);
if (error && error != boost::asio::error::message_size) {
throw boost::system::system_error(error);
}
receivedData[len] = '\0';
spdlog::info("Received UDP data: {}", receivedData);
}
catch (const std::exception& e) {
std::cerr << "Error receiving UDP data: " << e.what() << std::endl;
}
}
}
void tello::StartListening() {
std::thread udpThread(&tello::ReceiveThread, this);
udpThread.detach(); // Detach the thread so it runs independently
}
void tello::StopListening() {
isListening_ = false;
}
In my main.cpp I have this snippet to start the thread:
boost::asio::io_service io_service;
boost::asio::ip::udp::socket socket(io_service);
boost::asio::ip::udp::endpoint remote_endpoint(boost::asio::ip::address::from_string("192.168.0.1"), 12345); // Replace with the actual IP address and port
socket.open(boost::asio::ip::udp::v4());
tello drone(io_service, socket, remote_endpoint);
drone.StartListening();
The code compiles with no errors, but trying to run the app results in the console error:
Error receiving UDP data: An invalid argument was supplied [system:10022 at C:\Users\(username)\boost_1_82_0\boost\asio\detail\win_iocp_socket_service.hpp:418:5 in function 'receive_from']
I'm very new to Boost ASIO and would appreciate some help as to what the proper way to create a UDP receive thread. I'm using Windows 64bit with C++14. The full code is here on github
You have data races.
You start a thread which references both
io_serviceandsocketwhich are local variables inmain. However,mainexits immediately, destructing those local variables.The thread, which was detached, still runs causing Undefined Behaviour because of the stale references.
Fix it by
Also fixing some other issues and making up some code that might also be less safe (e.g. the potentially racy
isListening_). There are more issues hiding e.g.startListeningmay be more aptly namedstartReceivecatchblock seems inefficient since it would only handle the error thrown locallyLive On Coliru
Local demo:
BONUS
You want to use async IO so you can have much better behaviour. I think ironically it's a little bit simpler (about 30 LoC less):
Live On Coliru
And more local demo: