Струнный поток и многопоточность

Я новичок в многопоточности и C++, и у меня возникла проблема при попытке использовать потоки в моем приложении, которые сохраняют файлы. Код выглядит следующим образом:

#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;

}

Когда я запускаю эту программу, она печатает в терминале (подраздел результатов):

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

а также сохранение файлов со странными / неправильными именами файлов. Кажется, это проблема многопоточности и острингстрима, но есть идеи, почему / как это исправить?

2 ответа

Решение

Это не имеет ничего общего с многопоточностью.

const char* fileStr = filename.str().c_str();

std::ostringstream"s str() метод возвращает std::string представляет содержимое потока строки.

std::string"s c_str() Метод возвращает внутренний указатель на строковые данные.

Что вам не хватает, так это то, что указатель возвращается c_str() действует только до std::string модифицируется или уничтожается, в зависимости от того, что наступит раньше.

Вот std::string уничтожается немедленно, потому что это временное значение. Таким образом, указатель на его внутренние данные немедленно становится недействительным.

Вы должны сохранить возвращенную строку в объекте, который существует до тех пор, пока необходимы строковые данные. Просто:

std::string str = filename.str();
const char* fileStr = str.c_str();

str продолжает существовать до конца своей автоматической области, что достаточно долго, здесь.

В коде инициализации файла у вас есть следующий отрывок:

std::ostringstream filename;
...
filename << "test" << id << ".csv";
const char* fileStr = filename.str().c_str();

Эта последняя строчка убийца. То, что вы делаете, это забирает свой с трудом заработанный filename, получая string представление из него, извлекая c_str() указатель от него - а потом уничтожение временного string объект. С этого момента любая попытка доступа fileStr чревато

Что вам нужно сделать, это назначить временный string Объект для локальной переменной:

filename << "test" << id << ".csv";
std::string fileString = filename.str();
const char* fileStr = fileString.c_str();

Это гарантирует срок службы временного string объект - по крайней мере, до конца функции!

Без этого fileStr указывает на середину нераспределенной кучи - и куча меняется под ней.

Другие вопросы по тегам