多平台方法非常简单。避免使用标准指定应该使用哨兵的函数或运算符。 sentry 是 iostream 类中的一个内部类,它确保每个输出字符的流一致性,并且在多线程环境中,它为每个正在输出的字符锁定与流相关的互斥锁。这避免了低级别的竞争条件,但仍然使输出不可读,因为来自两个线程的字符串可能会同时输出,如下例所述:
线程 1 应该写:abc
线程 2 应该写:def
输出可能类似于:adebcf 而不是 abcdef 或 defabc。这是因为哨兵被实现为每个角色锁定和解锁。
该标准为所有处理 istream 或 ostream 的函数和运算符定义了它。避免这种情况的唯一方法是使用流缓冲区和您自己的锁定(例如每个字符串)。
我编写了一个应用程序,它将一些数据输出到文件并测量速度。如果您在此处添加一个直接使用 fstream 输出而不使用缓冲区和刷新的函数,您将看到速度差异。它使用boost,但我希望这对你来说不是问题。尝试删除所有流缓冲区,看看有无它们的区别。我的情况是性能缺陷是 2-3 倍左右。
N. Myers 的 following article 将解释 c++ IOStreams 中的语言环境和哨兵是如何工作的。当然,您应该查看 ISO C++ 标准文档,哪些函数使用哨兵。
祝你好运,
风向标
#include <vector>
#include <fstream>
#include <iterator>
#include <algorithm>
#include <iostream>
#include <cassert>
#include <cstdlib>
#include <boost/progress.hpp>
#include <boost/shared_ptr.hpp>
double do_copy_via_streambuf()
{
const size_t len = 1024*2048;
const size_t factor = 5;
::std::vector<char> data(len, 1);
std::vector<char> buffer(len*factor, 0);
::std::ofstream
ofs("test.dat", ::std::ios_base::binary|::std::ios_base::out);
noskipws(ofs);
std::streambuf* rdbuf = ofs.rdbuf()->pubsetbuf(&buffer[0], buffer.size());
::std::ostreambuf_iterator<char> oi(rdbuf);
boost::progress_timer pt;
for(size_t i=1; i<=250; ++i)
{
::std::copy(data.begin(), data.end(), oi);
if(0==i%factor)
rdbuf->pubsync();
}
ofs.flush();
double rate = 500 / pt.elapsed();
std::cout << rate << std::endl;
return rate;
}
void count_avarage(const char* op_name, double (*fct)())
{
double av_rate=0;
const size_t repeat = 1;
std::cout << "doing " << op_name << std::endl;
for(size_t i=0; i<repeat; ++i)
av_rate+=fct();
std::cout << "average rate for " << op_name << ": " << av_rate/repeat
<< "\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n"
<< std::endl;
}
int main()
{
count_avarage("copy via streambuf iterator", do_copy_via_streambuf);
return 0;
}