2

此函数以 ofstream 作为引用,然后构建结构数据包并使用 ofstream 将结构从结构中线程化到一个匹配类。按照匹配距离的顺序返回一个包含 n 个匹配项的堆栈。然后,ofstream、数据包和堆栈通过引用传递给打印函数,该函数将匹配项写入同一输出文件 - 等待 ofstream 不使用时。问题是在写入一半匹配项后 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);
    }
}

并在 ofstream 可用时打印

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

在多线程方面相当新,这些函数作为单线程工作得很好。

是否应该将检查 ofstream 可用放在衍生候选匹配的 while 循环中?一旦 ofstream 可用,则启动打印序列应将 ofstream 与其他线程绑定。

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

4

2 回答 2

3

如果您不熟悉多线程,那么让这成为您应该使用互斥锁的一个教训。

fstream对象就是——一个对象。您必须使用互斥锁来防止同时访问它。

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

于 2013-03-20T01:23:58.857 回答
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<<流实现由实现为您同步。在这个外部代码中你仍然有潜在的竞争。例如,这是跨 2 个线程的一种可能执行:

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

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

于 2013-03-20T01:23:02.623 回答