Я возился с приложением, которое использует boost :: asio для обмена данными как по UDP, так и по SocketCAN.
Сегодня я заметил что-то странное — утечка памяти!
Поэтому я взял свой верный инструментарий, состоящий из
echo 0 $(awk '/Private/ {print "+", $2}' /proc/`pidof main`/smaps) | bc
и Allinea DDT и приступили к диагностике этой проблемы.
В итоге я получил следующий фрагмент кода, в котором в качестве основы используется boost :: asio :: posix :: basic_stream_descriptor:
void Can::write(struct can_frame frame) {
stream_.async_write_some(boost::asio::buffer(&frame, sizeof(frame)),
boost::bind(&Can::datSend, this)
);
}
Здесь datSend — это просто пустая функция, которая пингует сторожевой таймер.
Я также пытался
void Can::write(struct can_frame frame) {
stream_.write_some(boost::asio::buffer(&frame, sizeof(frame)));
}
Но это дает исключение (неверные данные) по некоторым причинам.
Задняя часть этого кода выглядит примерно так:
boost::asio::io_service ioService_;
boost::asio::posix::basic_stream_descriptor<> stream_;
Constructor() : stream_(ioService_) {
socketDescriptor_ = socket(PF_CAN, SOCK_RAW, CAN_RAW);
struct timeval timeout {
.tv_sec = 5,
.tv_usec = 0
};
if (setsockopt(socketDescriptor_, SOL_SOCKET, SO_RCVTIMEO,
reinterpret_cast<char *>(&timeout),
sizeof(timeout)) < 0) {
throw std::string("Error setting CAN socket timeout");
}
strcpy(interfaceRequest_.ifr_name, interfaceName.c_str());
ioctl(socketDescriptor_, SIOCGIFINDEX, &interfaceRequest_);
socketAddress_.can_family = AF_CAN;
socketAddress_.can_ifindex = interfaceRequest_.ifr_ifindex;
stream_.assign(socketDescriptor_);
if (bind(socketDescriptor_, (struct sockaddr *)&socketAddress_,
sizeof(socketAddress_)) < 0) {
throw std::string("Error in socket bind");
}
}
После этого я просто запускаю ioservice и вот что:
void Can::iosThreadWorker() { ioService_.run(); }
Я перебрал немало тем, связанных с переполнением стека, а также дополнительную документацию, но, похоже, не могу понять, почему эта функция приводит к утечке памяти.
Буст-версия — 1.60
G ++ — 6.30
ОС: Ubuntu 17.04
Так что я покопался немного глубже и обнаружил эту новость о boost.io_service:
io_service.run () завершается, если у него нет работы, поэтому, запустив его и затем отправив больше асинхронной работы, работа не была завершена.
Это произошло из-за проблемы, когда кто-то перевернул назначение обратного вызова ioservice.run () и async read для того, чтобы код выглядел лучше — теперь не было работы, накопленной до запуска, и ioservice мог просто завершить свою работу и вернуться.
Других решений пока нет …