I'm new to multithreading and C++ and I'm having a problem when trying to use threads in my application which save files. The code is as follows:
#include <iostream>
#include <thread>
#include <fstream>
#include <vector>
#include <sstream>
using namespace std;
void writeCSV(vector<vector<double> > & vec, const char* filename) {
ofstream output(filename);
for (vector<vector<double> >::const_iterator i = vec.begin(); i != vec.end(); ++i) {
for (vector<double>::const_iterator j = i->begin(); j != --i->end(); ++j) {
output << *j << ", ";
}
output << *(--i->end()) << "\n";
}
}
void testFn(int id) {
std::ostringstream filename;
vector<vector<double> > v(460, vector<double>(460,0));
filename << "test" << id << ".csv";
const char* fileStr = filename.str().c_str();
cout << id << " : " << fileStr << endl;
writeCSV(v, fileStr);
}
int main() {
int numOfThreads = 180;
std::thread t[numOfThreads];
for (int i= 0; i< numOfThreads; i++) {
t[i] = std::thread (testFn, i);
}
for (int i = 0; i< numOfThreads; i++) {
t[i].join();
}
return 0;
}
When I run this program, it prints out in the terminal (subsection of results):
66 : 0�c
97 : test97.csv
90 : �'�dz
85 : �'�dz
43 :
9695 : �'�dz
67 : �'�dz
93 :
: �_ ��
115 : test115.csv
144 : test144.csv
99 : test99.c0
68 :
91 : )�
98 : test98.c0
as well as saving the files with weird/wrong filenames. This seems to be an issue from multithreading and ostringstream I guess, but any ideas why/how to fix?
This has nothing to do with multithreading.
const char* fileStr = filename.str().c_str();
std::ostringstream
's str()
method returns a std::string
representing the contents of the string stream.
A std::string
's c_str()
method returns an internal pointer to the string data.
What you're missing is that the pointer returned by c_str()
is only valid until either the std::string
is modified, or it is destroyed, whichever comes first.
Here std::string
gets destroyed immediately, because it is a temporary value. As such, a pointer to its internal data is immediately invalidated.
You must store the returned string in an object, that exists as long as the string data is needed. Simply:
std::string str = filename.str();
const char* fileStr = str.c_str();
str
continues to exist for the remainder of its automatic scope, which is long enough, here.