ofstream由多个线程共享 - 一段时间后崩溃

时间:2013-03-20 01:12:04

标签: c++ boost-thread ofstream

此函数将ofstream作为参考,然后使用ofstream将结构数据包和线程从结构构建到trie匹配类。以匹配距离的顺序返回具有n个匹配的堆栈。然后,ofstream,packet和stack通过引用传递给一个print函数,该函数将匹配写入相同的输出文件 - 等待ofstream未被使用。问题是在半场比赛结束后的比赛中崩溃了。

ofstream,packet和outfile标头

void Match_Import_Start(Trie & tri)
{
    stack<Trie::MatchesT> out;
    ofstream myfile;
    Trie::MatchesT matchSet;

    myfile.open(outFile.c_str() );
    myfile << "DESCRIPTION,SUGGESTED.DESCRIPTION,EDIT" << "\n"; //write header
    myfile.close();

    Match_Import (tri, myfile, out, matchSet);

    return;
}

从记录列表中生成线程

void Match_Import(Trie &tri, ofstream &myfile, stack<Trie::MatchesT> out, Trie::MatchesT matchSet)
{   
    out=parse_CSV_file(timeFile); //read in records

    settingT x;

    x.score=0;

    boost::thread_group tgroup; //http://stackoverflow.com/questions/8744279/create-threads-in-a-loop
    while (!out.empty() ) {
        matchSet=out.top();
        out.pop();

        tgroup.create_thread(boost::bind( MaxDistanceCorrections, boost::ref(tri), matchSet, boost::ref(myfile), boost::ref(x) ) );
    }
    tgroup.join_all();

    return;
}

检查匹配的有效回报

void MaxDistanceCorrections(Trie & tri, Trie::MatchesT matchSet, ofstream &myfile, settingT &x)
{
    if (!matchSet.candidateStack.empty() ) ) {
        matchSet.candidateStack.sort(compareCorrMain);
        PrintCorrections(tri, matchSet, myfile, x);
        return;

    } else {        
        tri.suggest(matchSet); //send out to trie match

         if (matchSet.candidateStack.empty() ) { }// modify match parameters

        MaxDistanceCorrections(tri, matchSet, myfile, x);
    }
}

并在有可用时打印

void PrintCorrections(Trie &tri, Trie::MatchesT &matchSet, ofstream &myfile, settingT &x)
{   
    while (true) {
        if (!myfile.is_open() ) { 
          myfile.open(outFile.c_str(), ios::out | ios::app);
          break;
        }  
     }

    while (!matchSet.candidateStack.empty() ) {
        Trie::CorrectionT corr=matchSet.candidateStack.back();
        matchSet.candidateStack.pop_back();

        const bool flagGood=scoreSuggest (corr); //score
        if (flagGood ) x.score++;

        myfile << matchSet.testCase << "," << corr.match << "," << corr.editDistance << "\n";

    }
    myfile.close();

    return;
}

在mutithreading上相当新,这些函数作为单个线程运行良好。

是否可以将ofstream流检查放在while循环中,以便旋转候选匹配?一旦有可用的流,那么启动打印序列应该将其他线程的流组合起来。

有没有更好的方法来保留使用多个线程共享的ofstream?

2 个答案:

答案 0 :(得分:2)

此代码表示来自多个线程的未定义行为。见N3485 27.2.3 [iostreams.threadsafety] / 1:

  

除非另有说明(27.4),否则多个线程对流对象(27.8,27.9),流缓冲区对象(27.6)或C库流(27.9.2)的并发访问可能会导致数据竞争(1.10)。 [注意:数据争用导致未定义的行为(1.10)。 - 后注]

在一般情况下,跨线程使用流是不安全的。您必须使用锁定来保护流,例如std::mutex

请注意,即使流可以安全地跨线程访问,此代码也可能无法执行您想要的操作。考虑这一行:

myfile << matchSet.testCase << "," << corr.match << corr.editDistance << "\n";

相同
myfile << matchSet.testCase;
myfile << ",";
myfile << corr.match;
myfile << corr.editDistance;
myfile << "\n";

注意比赛条件。假设您的实现的流operator<<由实现同步。你仍然在这个外部代码中有潜在的竞争。例如,这里有两个线程可能执行此操作:

   Thread 1                              Thread 2
======================================================================
myfile << matchSet.testCase;
                                         myfile << matchSet.testCase;
myfile << ",";
                                         myfile << ",";
myfile << corr.match;
myfile << corr.editDistance;
myfile << "\n";
                                         myfile << corr.match;
                                         myfile << corr.editDistance;
                                         myfile << "\n";

不是将它写成一行,而是将每个线程的输出混合在一起,导致乱码。

答案 1 :(得分:2)

如果您不熟悉多线程,请告诉我们您应该使用互斥锁的原因。

fstream对象只是一个对象。您必须使用互斥锁保护它免受同时访问。

如果您只是希望线程能够将信息写入文件,则可以改为传递文件名(作为string)而不是fstream。然后,线程可以使用独占读/写访问权限打开文件。这将使用本地fstream对象,锁定将由操作系统处理。