I have a function I call with std::async, and sometimes it throws an exception and sometimes not. I cannot really get hold of the bug, so I was hoping someone could point me into the right direction.
Its a lot of code, so I will try to wrap up what I think are the basic parts. The error I get is this one
Unhandled exception at 0x77EC897E (ntdll.dll) in Dodgson.exe: 0xC000000D: An invalid parameter was passed to a service or function.
in the VS2010 Break/Continue dialogue box.
Base.h
class Base {
public:
void threadControl(int maxThreads);
virtual void threadCode(Data n) = 0;
private:
vector<future<void>> m_futures;
mutex m_mutex;
atomic<int> m_minimum;
vector<Data> m_winData; // as this is shared data, i would like to make it atomic or volatile, but that won't work. Having a mutex must suffice.
}
Base.cpp
void Base::threadControl(int maxThreads) {
vector<Data> queue = Somewhere::readData();
while( !queue.empty() ) {
if( m_futures.size() < maxThreads ) {
m_futures.push_back(std::async(std::launch::async, &Base::threadCode, this, queue.back())); // this works properly
queue.pop_back();
} else {
// I think this might be a critical part. This code tries to look for finished threads and deletes them from the thread-holder m_futures
for( unsigned int i=0; i<m_futures.size(); i++ ) {
if( m_futures[i].wait_for(chrono::milliseconds(10))==std::future_status::ready ) {
m_futures.erase(m_futures.begin()+i);
i--;
}
}
}
}
// waiting for all still running threads to finish
for( unsigned int i=0; i<m_futures.size(); i++ ) {
m_futures[i].get();
}
}
Impl.h
class Impl : public Base {
virtual void threadCode(Data n);
}
Impl.cpp
void Impl::threadCode(Data n) {
while( !n.empty() ) {
// .. work on next data block, get a "local minimum value" for it. Compare it with "global minimum value" m_minimum, which all threads can manipulate. This should be a critical stage too.
int localMinimum = Somewhere::getMinimum(n.current());
m_mutex.lock();
if( m_minimum > localMinimum ) {
m_minimum = localMinimum;
m_winData.push_back(n.current());
}
m_mutex.unlock();
n.pop();
}
}
I hope I didn't overdo it with the code. However, if anything is unclear I am happy to provide more information.
The VS2010 callstack had nothing I could understand, just a quick peek into the last 10 of ~50 calls:
ntdll.dll!77e52289() Unknown [Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
ntdll.dll!77ec87a7() Unknownmsvcr110d.dll!__crtSetThreadpoolTimer(_TP_TIMER * pti, _FILETIME * pftDueTime, unsigned long msPeriod, unsigned long msWindowLength) Line 521 C msvcr110d.dll!__crtWaitForThreadpoolTimerCallbacks(_TP_TIMER * pti, int fCancelPendingCallbacks) Line 539 C msvcr110d.dll!Concurrency::details::EventWaitNode::Satisfy(Concurrency::Context * * pContextOut) Line 330 C++ msvcr110d.dll!Concurrency::details::_Condition_variable::notify_all() Line 688 C++ msvcp110d.dll!do_signal(_Cnd_internal_imp_t * * cond, int all) Line 65 C++ msvcp110d.dll!_Cnd_broadcast(_Cnd_internal_imp_t * * cond) Line 88 C++ My_Program.exe!std::_Cnd_broadcastX(_Cnd_internal_imp_t * * _Cnd) Line 103 C++ My_Program.exe!std::condition_variable::notify_all() Line 55 C++ My_Program.exe!std::_Associated_state::_Do_notify(std::unique_lock * _Lock, bool _At_thread_exit) Line 549 C++
... and many more
Last but not least, it is most likely a timing issue. While debugging, I filled one implementation with many lines such as "cout << "2" << endl;" in order to narrow the position of the bug down.
This lead to that implementation running into the bug much less likely. While before it would usually crash after ~3 seconds of running its code, it now, most of the time, runs for ~5 minutes and terminates normally. All other implementations without the comments still run into the bug after ~3 seconds. So I guess that slowing the program down by printing ~100 lines of text to the console each second "solves" the issue.
..I do not want to fix my code like this.
User contributions licensed under CC BY-SA 3.0