stringstream和多线程

Bil*_*lly 2 c++ multithreading ostringstream ofstream

我是多线程和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;

}
Run Code Online (Sandbox Code Playgroud)

当我运行这个程序时,它会在终端打印出来(结果的子部分):

66 : 0?c
97 : test97.csv
90 : ?'??
85 : ?'??
43 : 
9695 : ?'??
67 : ?'??
93 : 
 : ?_   ??
115 : test115.csv
144 : test144.csv
99 : test99.c0
68 : 
91 :  )?
98 : test98.c0
Run Code Online (Sandbox Code Playgroud)

以及使用奇怪/错误的文件名保存文件.这似乎是多线程和ostringstream的问题,我想,但任何想法为什么/如何解决?

Sam*_*hik 6

这与多线程无关.

const char* fileStr = filename.str().c_str();
Run Code Online (Sandbox Code Playgroud)

std::ostringstreamstr()方法返回一个std::string表示字符串流内容的方法.

std::stringc_str()方法返回的内部指针字符串数据.

你所缺少的是返回的指针c_str()只有在std::string被修改或被破坏之前才有效,以先到者为准.

这里std::string立即被销毁,因为它是一个临时值.因此,指向其内部数据的指针立即失效.

必须将返回的字符串存储在对象中,只要需要字符串数据,该对象就存在.只是:

std::string str = filename.str();
const char* fileStr = str.c_str();
Run Code Online (Sandbox Code Playgroud)

str 继续存在其自动范围的剩余部分,这在这里足够长.


Joh*_*ger 5

在您的文件初始化代码中,您有以下摘录:

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

最后一句是杀手锏。您所做的就是获取来之不易的filenamestring从中获取表示形式,c_str()从中提取指针 - 然后销毁临时string对象。从那时起,任何访问尝试fileStr都会充满风险。

您需要做的是将临时string对象分配给局部变量:

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

这保证了临时对象的生命周期string- 至少直到函数结束!

如果不这样做,fileStr则指向未分配堆的中间 - 并且堆在其下面发生变化。