seg fault on windows with Boost threads, istringstream, mingw

Hi I am working on a multithreaded application for linux and windows using Boost threads. For windows, we have been developing with MinGW G++ 3.4.4 (packaged in cygwin). My application uses a producer-consumer model where one thread produces tasks definitions and multiple worker threads complete the tasks. I discovered that our application runs fine on linux but crashes with a SIGSEGV fault on windows, at least when compiled with MinGW. When compiling the same application with MSVC it works fine. The SIGSEGV crash is not always in the exact same place in the code, but is very likely to occur -- it happens 99% of the time when there are 3 or more worker threads. The code runs fine if there is only 1 worker thread. If I try to use the debugger to get a stack trace, I find the stack is corrupted so I can not see the method or source code lines that caused the crash. I have tried boost 1.36 and 1.37. I have tried MinGW g++ 3.4.4 (from cygwin), 3.4.5 (main release) and 4.3 (alpha). I get the same results in all cases. I have added the -mthreads flag to the compile and link options for my application. I believe the problem is related to this code, which uses a istringstream to convert a string to a basic type (say a double): template <typename T> bool FromString(T &t,const std::string &s, std::ios_base &(*f)(std::ios_base &)=std::dec) { std::istringstream iss(s); return !(iss >> f >> t).fail(); } The istringstream object is local to the conversion function, and each istringstream is unique for each thread. So I wouldn't expect a thread-related problem, unless istringstream has internal state stored in static variables. However, if I replace that code with equivalent calls to C-lib functions like 'atof', the problem goes away. I have attached a test application, along with the makefile I use to build it, that demonstrates this problem. This test application fails for with a SIGSEGV when run with MinGW GCC 3.4.4 (from cygwin), MinGW 3.4.5 (current MinGW release) or MinGW GCC 4.3 alpha. It works fine when I compile with MSVC or Cygwin GCC (non-mingw version based on cygwin1.dll and pthreads). I hope there is a solution but at this point and hope for some help answering these questions: 1) Is there a multi-thread bug in the MinGW implementation istringstream? 2) Is there a problem with my build process? Am I missing a flag or using the wrong variation of a library? 3) Is this problem unique to my machine or reproducible by others? 4) Has anyone else encountered a similar issue? If you have experience with using Boost threads with MinGW I would love to hear any pointers or suggestions you can share. If you try this test application with MinGW G++ and it works I would love to know it. If multiple people can confirm this is a bug, I want to submit it to either the MinGW or Boost threads dev. teams. Thanks in advance for your help, Tod Courtney -- Tod Courtney Delcross Technologies LLC tcourtney@delcross.com, www.delcross.com (217) 363-3396 ext 103 mingw34: test.cpp c:\\MinGW\\bin\\g++ -mthreads -o mingw34 test.cpp -I c:\\boost\\boost_1_37_0 -L c:\\boost\\boost_1_37_0\\stage\lib -lboost_thread-mgw34-mt newmingw43: test.cpp c:\\mingw4\\bin\\g++ -mthreads -o newmingw43 test.cpp -I c:\\boost\\boost_1_37_0 -L c:\\boost\\boost_1_37_0\\stage\\lib -lboost_thread-mgw43-mt nocygwin: test.cpp /usr/bin/g++ -mthreads -o nocygwin test.cpp -I /cygdrive/c/boost/boost_1_37_0 -L /cygdrive/c/boost/boost_1_37_0/stage/lib -mno-cygwin -lboost_thread-mgw34-mt cygwin: test.cpp /usr/bin/g++ -o cygwin test.cpp -I /cygdrive/c/boost/boost_1_37_0 -L /cygdrive/c/boost/boost_1_37_0/stage/lib -lboost_thread_pthread-gcc34-mt-1_37 #include <string> #include <vector> #include "boost/bind.hpp" #include "boost/thread.hpp" #include "boost/thread/barrier.hpp" using namespace std; boost::mutex msgMutex; //////////////////////////////////////////////////////////////////////// /// threadsafe tracing method void msg(const std::string &str) { boost::mutex::scoped_lock lock(msgMutex); cout<<str<<endl; } //////////////////////////////////////////////////////////////////////// /// method run by each worker thread bool exec(std::vector<string> * vec) { char buff[256]; // wait here until all threads have been created msg(string("START THREAD: ")); // now do the work for(size_t n=0;n<vec->size();n++) { string val=(*vec)[n]; double d=0; d=atof(val.c_str()); // COMMENTING OUT THE NEXT TWO LINES AVOIDS THE SIGSEGV istringstream iss(val); iss>>d; sprintf(buff,"value=%lf",d); msg(string(buff)); } msg("EXEC DONE: "); return true; } //////////////////////////////////////////////////////////////////////// /// main method: parse inputs and create worker threads int main(int argc, char **argv) { int numThreads=0; if (argc==2) numThreads=atoi(argv[1]); else cout<<"USAGE: "<<argv[0]<<" <numthreads>"<<endl; boost::thread **worker; vector<string> **vec; worker=new boost::thread*[numThreads]; vec=new vector<string>*[numThreads]; for(int n=0;n<numThreads;n++) { vec[n]=new vector<string>; for(int m=0;m<10;m++) { ostringstream oss; oss<<n<<"."<<m; vec[n]->push_back(oss.str()); } worker[n]=new boost::thread(boost::bind(&exec,vec[n])); } // wait until all threads to end for(int n=0;n<numThreads;n++) { worker[n]->join(); delete worker[n]; delete vec[n]; } delete [] worker; delete [] vec; }

Tod Courtney wrote:
I believe the problem is related to this code, which uses a istringstream to convert a string to a basic type (say a double):
template <typename T> bool FromString(T &t,const std::string &s, std::ios_base &(*f)(std::ios_base &)=std::dec) { std::istringstream iss(s); return !(iss >> f >> t).fail(); }
Somewhat off-topic, but couldn't you maybe use boost::lexical_cast to do this?
1) Is there a multi-thread bug in the MinGW implementation istringstream?
If there is, I wouldn't call it a bug. The standard library makes no guarantees about thread safety. For all you know a std::string implementation could internally reference-count its buffers in a non-thread-safe way.
// wait until all threads to end for(int n=0;n<numThreads;n++) { worker[n]->join(); delete worker[n]; delete vec[n]; }
Does moving the two delete calls outside of this loop so that no deletes happen until all threads have finished fix the problem? If so, you might consider using boost::ptr_vector to eliminate the explicit deletes and simplify some of the allocation code.
participants (2)
-
Kenny Riddile
-
Tod Courtney