boost::asio::io_context::stop gtest 安装和拆卸中的 segfalt
boost::asio::io_context::stop segfalt in gtest setup and teardown
使用 C++17。我正在尝试设置一个 gtest 装置,它将为每个测试用例创建一个新的 io_context 到 运行 计时器。我的测试 segfault 大约有 90% 的时间。如果我调试和步进非常慢,我可以一直到 运行。
我不确定这里发生了什么。我已经每隔 运行 创建了一个新线程和新 ioservice,只是为了确保没有从以前的测试中遗留。然后我完全删除了测试内容以缩小范围。它会引发停止调用。
#include "gtest/gtest.h"
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <iostream>
class TrafficLightTestSuite : public testing::Test
{
public:
protected:
boost::asio::io_context * m_ioContext;
boost::thread * m_ioThread;
void SetUp() override
{
std::cout << "Setup" << std::endl;
m_ioThread = new boost::thread([&]()
{
m_ioContext = new boost::asio::io_context();
std::cout << "IO Service created" << std::endl;
// Keep the io service alive until we are done
boost::asio::io_service::work work(*m_ioContext);
m_ioContext->run();
std::cout << "IO Context run exited" << std::endl;
delete m_ioContext;
m_ioContext = nullptr;
std::cout << "IO Context deleted" << std::endl;
});
}
void TearDown() override
{
std::cout << "Tear down stopping IO Context" << std::endl;
m_ioContext->stop();
m_ioThread->join();
std::cout << "Thread exit" << std::endl;
delete m_ioThread;
}
};
TEST_F(TrafficLightTestSuite, testTimeLapse)
{
std::cout << "Performing test" << std::endl;
}
运行宁时的输出:
Testing started at 1:49 PM ...
Setup
Performing test
Tear down stopping IO Context
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
使用调试器单步执行时的输出:
Testing started at 1:55 PM ...
Setup
IO Service created
Performing test
Tear down stopping IO Context
IO Context run exited
IO Context deleted
Thread exit
Process finished with exit code 0
io_context 必须是线程安全的,不然你怎么告诉它停止?
有人发现问题了吗?
m_ioContext->stop();
发生在 m_ioContext = new boost::asio::io_context();
之前。只需将其创建移动到 SetUp
并将删除移动到 TearDown
。你甚至不需要指点。
#include "gtest/gtest.h"
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <iostream>
class TrafficLightTestSuite : public testing::Test
{
public:
protected:
boost::asio::io_context m_ioContext{};
boost::thread m_ioThread{};
void SetUp() override
{
std::cout << "Setup" << std::endl;
std::cout << "IO Service created" << std::endl;
m_ioThread = boost::thread([&]()
{
// Keep the io service alive until we are done
boost::asio::io_service::work work(m_ioContext);
m_ioContext.run();
std::cout << "IO Context run exited" << std::endl;
});
}
void TearDown() override
{
std::cout << "Tear down stopping IO Context" << std::endl;
m_ioContext.stop();
m_ioThread.join();
std::cout << "Thread exit" << std::endl;
std::cout << "IO Context deleted" << std::endl;
}
};
TEST_F(TrafficLightTestSuite, testTimeLapse)
{
std::cout << "Performing test" << std::endl;
}
问题是无法保证在主线程恢复执行之前线程上的任何内容都会执行。这导致了在执行测试用例之前未创建 ioservice 和 运行 的问题,假设 ioservice 将是 运行.
这可以通过使用可以等待的信号量来修复,并在调用 ioservice::run 之前在该信号量上排队 post。这样,一旦 ioservice 运行,信号量 posts 和测试用例就无法执行,直到发生这种情况。
class TrafficLightTestSuite : public testing::Test
{
public:
protected:
boost::asio::io_context m_ioContext {};
boost::asio::io_service::work m_work {m_ioContext}; // Keeps the ioservice running when nothing is posted
boost::thread m_ioThread {};
boost::interprocess::interprocess_semaphore m_semaphore {0};
void SetUp() override
{
// When the ioservice starts up, the semaphore will notify anyone that was waiting on it to run
m_ioContext.post([&]() { m_semaphore.post(); });
// Run the io service on its own thread, where completion handlers will be called
m_ioThread = boost::thread(boost::bind(&boost::asio::io_service::run, &m_ioContext));
// Test cases should wait on the semaphore to ensure the io service is running before they execute.
// In production environment, you'd probably init the ioservice in some manner of application setup and do a
// similar notification when everything was initialized.
m_semaphore.wait();
}
void TearDown() override
{
m_ioContext.stop();
m_ioThread.join();
}
};
TEST_F(TrafficLightTestSuite, testInitialColor)
{
// This is guaranteed not to execute until the ioservice is running
}
您还可以使用条件变量创建自己的信号量。如果使用 C++20,可以使用标准信号量,
使用 C++17。我正在尝试设置一个 gtest 装置,它将为每个测试用例创建一个新的 io_context 到 运行 计时器。我的测试 segfault 大约有 90% 的时间。如果我调试和步进非常慢,我可以一直到 运行。
我不确定这里发生了什么。我已经每隔 运行 创建了一个新线程和新 ioservice,只是为了确保没有从以前的测试中遗留。然后我完全删除了测试内容以缩小范围。它会引发停止调用。
#include "gtest/gtest.h"
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <iostream>
class TrafficLightTestSuite : public testing::Test
{
public:
protected:
boost::asio::io_context * m_ioContext;
boost::thread * m_ioThread;
void SetUp() override
{
std::cout << "Setup" << std::endl;
m_ioThread = new boost::thread([&]()
{
m_ioContext = new boost::asio::io_context();
std::cout << "IO Service created" << std::endl;
// Keep the io service alive until we are done
boost::asio::io_service::work work(*m_ioContext);
m_ioContext->run();
std::cout << "IO Context run exited" << std::endl;
delete m_ioContext;
m_ioContext = nullptr;
std::cout << "IO Context deleted" << std::endl;
});
}
void TearDown() override
{
std::cout << "Tear down stopping IO Context" << std::endl;
m_ioContext->stop();
m_ioThread->join();
std::cout << "Thread exit" << std::endl;
delete m_ioThread;
}
};
TEST_F(TrafficLightTestSuite, testTimeLapse)
{
std::cout << "Performing test" << std::endl;
}
运行宁时的输出:
Testing started at 1:49 PM ...
Setup
Performing test
Tear down stopping IO Context
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
使用调试器单步执行时的输出:
Testing started at 1:55 PM ...
Setup
IO Service created
Performing test
Tear down stopping IO Context
IO Context run exited
IO Context deleted
Thread exit
Process finished with exit code 0
io_context 必须是线程安全的,不然你怎么告诉它停止? 有人发现问题了吗?
m_ioContext->stop();
发生在 m_ioContext = new boost::asio::io_context();
之前。只需将其创建移动到 SetUp
并将删除移动到 TearDown
。你甚至不需要指点。
#include "gtest/gtest.h"
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <iostream>
class TrafficLightTestSuite : public testing::Test
{
public:
protected:
boost::asio::io_context m_ioContext{};
boost::thread m_ioThread{};
void SetUp() override
{
std::cout << "Setup" << std::endl;
std::cout << "IO Service created" << std::endl;
m_ioThread = boost::thread([&]()
{
// Keep the io service alive until we are done
boost::asio::io_service::work work(m_ioContext);
m_ioContext.run();
std::cout << "IO Context run exited" << std::endl;
});
}
void TearDown() override
{
std::cout << "Tear down stopping IO Context" << std::endl;
m_ioContext.stop();
m_ioThread.join();
std::cout << "Thread exit" << std::endl;
std::cout << "IO Context deleted" << std::endl;
}
};
TEST_F(TrafficLightTestSuite, testTimeLapse)
{
std::cout << "Performing test" << std::endl;
}
问题是无法保证在主线程恢复执行之前线程上的任何内容都会执行。这导致了在执行测试用例之前未创建 ioservice 和 运行 的问题,假设 ioservice 将是 运行.
这可以通过使用可以等待的信号量来修复,并在调用 ioservice::run 之前在该信号量上排队 post。这样,一旦 ioservice 运行,信号量 posts 和测试用例就无法执行,直到发生这种情况。
class TrafficLightTestSuite : public testing::Test
{
public:
protected:
boost::asio::io_context m_ioContext {};
boost::asio::io_service::work m_work {m_ioContext}; // Keeps the ioservice running when nothing is posted
boost::thread m_ioThread {};
boost::interprocess::interprocess_semaphore m_semaphore {0};
void SetUp() override
{
// When the ioservice starts up, the semaphore will notify anyone that was waiting on it to run
m_ioContext.post([&]() { m_semaphore.post(); });
// Run the io service on its own thread, where completion handlers will be called
m_ioThread = boost::thread(boost::bind(&boost::asio::io_service::run, &m_ioContext));
// Test cases should wait on the semaphore to ensure the io service is running before they execute.
// In production environment, you'd probably init the ioservice in some manner of application setup and do a
// similar notification when everything was initialized.
m_semaphore.wait();
}
void TearDown() override
{
m_ioContext.stop();
m_ioThread.join();
}
};
TEST_F(TrafficLightTestSuite, testInitialColor)
{
// This is guaranteed not to execute until the ioservice is running
}
您还可以使用条件变量创建自己的信号量。如果使用 C++20,可以使用标准信号量,