Still trying to figure out what is happening with ADODB's connections and why a certain crash is occuring.
The problem was that we had a memory leak in our code:
void getDetailConfig()
{
m_displayConf = new TestDetailDisplayCfg();
}
This function is called often so a basic memory leak. Fixed it with a unique pointer
void getDetailConfig()
{
m_displayConf = std::make_unique<TestDetailDisplayCfg>();
}
Yay party, but now an acces violation started to happen inside ADODB's Recordset15::Close.
inline HRESULT Recordset15::Close ( ) {
HRESULT _hr = raw_Close();
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _hr;
}
Unhandled exception at 0x679E653F (msado15.dll) in LaneControl.exe: 0xC000041D: An unhandled exception was encountered during a user callback.
So calling all destructors the right way caused a new issue, there are recordset's opened and closed somewhere.
After debugging it turns out that getDetailConfig is called from two different threads.
Thread1
void updateIconStatus()
{
getDetailConfig();
}
Thread ID 5bA8
Thread2
void CVTSDetailDisplay::setCurrentTestIconStatus(int status)
{
m_CurrentDialog->getDetailConfig();
}
Thread ID 6A4C
So these 2 threads call getDetailConfig where a recordset is closed which was opened on another thread and COM objects are Released and what not.
Is that a problem that you can't close ADO recordsets on another thread? Is it more a race condition? What is going wrong here at ADODB's level?
I'd think it is a race condition.
If the getDetailConfig()
function was already called before, and then both threads call the getDetailConfig()
, this can result in both threads calling the destructor (of the object which was there before) simultaneously (std::unique_ptr
is not inherently thread-safe AFAIK).
You'd then need to ensure critical section for the exchange of the pointers, for example adding std::mutex m_mutex;
as a member of your class (ideally to the first place in the members list so it remains valid longer than the m_displayConf
member) and then adding
void getDetailConfig()
{
std::unique_lock<std::mutex> lock(m_mutex);
m_displayConf = std::make_unique<TestDetailDisplayCfg>();
}
to make sure the exchange is locked between threads.
User contributions licensed under CC BY-SA 3.0