`std::osyncstream` 如何管理输出流?
How does `std::osyncstream` manage the out stream?
我想知道 std::osyncstream
对象如何防止数据竞争条件?它是否锁定了一些互斥体?
我具体说的是下面这个程序:
#include <iostream>
#include <fstream>
#include <thread>
#include <syncstream>
void worker( const std::size_t startValue, const std::size_t stopValue, std::ostream& os )
{
for ( auto idx { startValue }; idx < stopValue; ++idx )
{
std::osyncstream out { os };
out << "thread: " << std::this_thread::get_id( ) << "; work: " << idx << '\n';
}
}
void runThreads( std::ostream& os )
{
std::jthread t1 { worker, 10000, 20000, std::ref( os ) };
std::jthread t2 { worker, 20000, 30000, std::ref( os ) };
}
int main( )
{
std::ofstream file { "out.txt" };
runThreads( file );
}
以上代码源码可查看here。虽然我做了一些细微的修改,让它变得更好更安全。
这个简单的程序将 20,000 行打印到一个文件中,而不会产生混乱的输出。
可能的输出:
thread: 2; work: 10000
thread: 3; work: 20000
thread: 2; work: 10001
thread: 2; work: 10002
thread: 2; work: 10003
thread: 2; work: 10004
thread: 2; work: 10005
thread: 2; work: 10006
.
.
.
幕后发生了什么?这两个线程如何相互通信?他们有单独的 syncstream
对象副本吗?这个对象(即out
)如何管理输出流os
?
Does it lock some mutex?
是的,间接的。 std::basic_osyncstream
class,其中 osyncstream
是 basic_osyncstream<char>
形式的特例,派生自 std::basic_ostream
,通常只有一个 'extra' std::basic_syncbuf
class 的成员。 From cppreference:
Typical implementation of std::basic_osyncstream holds only one
member: the wrapped std::basic_syncbuf.
正是basic_syncbuf
对象实现了输出同步,防止了数据竞争。同样,from cppreference(加粗我的):
Typical implementation of std::basic_syncbuf holds a pointer to the
wrapped std::basic_streambuf, a boolean flag indicating whether the
buffer will transmit its contents to the wrapped buffer on sync
(flush), a boolean flag indicating a pending flush when the policy is
to not emit on sync, an internal buffer that uses Allocator (such as
std::string), and a pointer to a mutex used to synchronize emit
between multiple threads accessing the same wrapped stream buffer
(these mutexes may be in a hash map with pointers to basic_streambuf
objects used as keys).
我想知道 std::osyncstream
对象如何防止数据竞争条件?它是否锁定了一些互斥体?
我具体说的是下面这个程序:
#include <iostream>
#include <fstream>
#include <thread>
#include <syncstream>
void worker( const std::size_t startValue, const std::size_t stopValue, std::ostream& os )
{
for ( auto idx { startValue }; idx < stopValue; ++idx )
{
std::osyncstream out { os };
out << "thread: " << std::this_thread::get_id( ) << "; work: " << idx << '\n';
}
}
void runThreads( std::ostream& os )
{
std::jthread t1 { worker, 10000, 20000, std::ref( os ) };
std::jthread t2 { worker, 20000, 30000, std::ref( os ) };
}
int main( )
{
std::ofstream file { "out.txt" };
runThreads( file );
}
以上代码源码可查看here。虽然我做了一些细微的修改,让它变得更好更安全。
这个简单的程序将 20,000 行打印到一个文件中,而不会产生混乱的输出。
可能的输出:
thread: 2; work: 10000
thread: 3; work: 20000
thread: 2; work: 10001
thread: 2; work: 10002
thread: 2; work: 10003
thread: 2; work: 10004
thread: 2; work: 10005
thread: 2; work: 10006
.
.
.
幕后发生了什么?这两个线程如何相互通信?他们有单独的 syncstream
对象副本吗?这个对象(即out
)如何管理输出流os
?
Does it lock some mutex?
是的,间接的。 std::basic_osyncstream
class,其中 osyncstream
是 basic_osyncstream<char>
形式的特例,派生自 std::basic_ostream
,通常只有一个 'extra' std::basic_syncbuf
class 的成员。 From cppreference:
Typical implementation of std::basic_osyncstream holds only one member: the wrapped std::basic_syncbuf.
正是basic_syncbuf
对象实现了输出同步,防止了数据竞争。同样,from cppreference(加粗我的):
Typical implementation of std::basic_syncbuf holds a pointer to the wrapped std::basic_streambuf, a boolean flag indicating whether the buffer will transmit its contents to the wrapped buffer on sync (flush), a boolean flag indicating a pending flush when the policy is to not emit on sync, an internal buffer that uses Allocator (such as std::string), and a pointer to a mutex used to synchronize emit between multiple threads accessing the same wrapped stream buffer (these mutexes may be in a hash map with pointers to basic_streambuf objects used as keys).