мультиплатформенный подход довольно прост. Избегайте функций или операторов, где стандарт указывает, что они должны использовать часового. sentry - это внутренний класс в классах iostream, который обеспечивает согласованность потоков для каждого выходного символа, а в многопоточной среде он блокирует мьютекс, связанный с потоком, для каждого выводимого символа. Это позволяет избежать состояния гонки на низком уровне, но при этом делает вывод нечитаемым, поскольку строки из двух потоков могут выводиться одновременно, как показано в следующем примере:
Тема 1 должна написать: abc
поток 2 должен написать: def
Вывод может выглядеть следующим образом: adebcf вместо abcdef или defabc. Это связано с тем, что часовой механизм реализован для блокировки и разблокировки каждого символа.
Стандарт определяет его для всех функций и операторов, работающих с istream или ostream. Единственный способ избежать этого - использовать потоковые буферы и собственную блокировку (например, для каждой строки).
Я написал приложение, которое выводит некоторые данные в файл и измеряет скорость. Если вы добавите сюда функцию, которая выходит непосредственно с использованием fstream, без использования буфера и сброса, вы увидите разницу в скорости. Это использует повышение, но я надеюсь, что это не проблема для вас. Попробуйте удалить все потоковые буферы и увидеть разницу с ними и без них. В моем случае недостаток производительности составлял 2-3 раза.
Следующая статья Н. Майерса объяснит, как работают локали и часовые в c ++ IOStreams. И наверняка вам следует поискать в документе ISO C ++ Standard, какие функции используют sentry.
Удачи,
Ованес
#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;
}