此函数将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?
答案 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
对象,锁定将由操作系统处理。