Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/133.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ istream和ostream具有共享的streambuf,对于双工I/O是线程安全的?_C++_Multithreading_Sockets_Stream_Iostream - Fatal编程技术网

C++ istream和ostream具有共享的streambuf,对于双工I/O是线程安全的?

C++ istream和ostream具有共享的streambuf,对于双工I/O是线程安全的?,c++,multithreading,sockets,stream,iostream,C++,Multithreading,Sockets,Stream,Iostream,我已经为缓冲的网络套接字I/O派生了一个自定义streambuf,它覆盖了下溢、溢出和同步,这样下溢和其他两个的集合是线程安全的(我有单独的输入和输出内部缓冲区)。这很好,但我想将其用于全双工I/O,其中一个线程可以输入,而另一个线程可以输出,因此我想对接收线程使用istream,对发送线程使用ostream,同时共享网络流BUF,因为它抽象了所有套接字内容。我的问题是,如果输入和输出缓冲区是分开的,那么istream上的输入操作对streambuf成员的影响程度与ostream上的输出操作对s

我已经为缓冲的网络套接字I/O派生了一个自定义streambuf,它覆盖了下溢、溢出和同步,这样下溢和其他两个的集合是线程安全的(我有单独的输入和输出内部缓冲区)。这很好,但我想将其用于全双工I/O,其中一个线程可以输入,而另一个线程可以输出,因此我想对接收线程使用istream,对发送线程使用ostream,同时共享网络流BUF,因为它抽象了所有套接字内容。我的问题是,如果输入和输出缓冲区是分开的,那么istream上的输入操作对streambuf成员的影响程度与ostream上的输出操作对streambuf成员的影响程度如何


更好的做法是能够做到这一点,而不是必须将套接字内容从我的streambuf抽象中分离出来,这样就可以使用单独的streambuf在istream和ostream之间共享套接字——然后我还需要两个版本的streambuf——一个具有单个内部缓冲区(仅用于istream或ostream),还有一个像我现在一样有两个内部缓冲区,用于iostream。。。很糟糕,因为这是额外的类和代码复制。

输入和输出序列基本上是独立的。下面有一个很好的图表:

输入和输出序列之间唯一共享的是
locale
对象,该对象包含用于执行文本编码转换的
codevt
方面

理论上,中途更改文本编码是线程不安全的,但实际上库根本不支持该操作


你应该可以走了。

没有为
std::streambuf
(或
std::basic_streambuf
)提供比一般情况下更多的保证。也就是说,您可以让多个线程在任何时候读取对象的状态,但是如果有一个线程修改对象的状态,那么就不会有其他线程访问对象。读取和写入字符都会修改流缓冲区的状态,即从形式上看,如果没有外部同步,就不能使用它们

在内部,这两个缓冲区是完全分开的,彼此没有任何关系。流缓冲区上的操作以一种相当结构化的方式修改它们,我无法想象任何实现都会在两组指针之间有显式的交互。也就是说,在实际应用中,我认为阅读和写作之间不需要任何同步。但是,我以前没有意识到这两组缓冲区指针实际上可能共享相同的缓存线,这至少会导致性能问题。我不认为这会导致任何正确性问题

两个流缓冲区之间可能共享的唯一资源是
std::locale
对象,但是该对象是无状态的。另外,
std::streambuf
不会使用此对象本身:它是您的流缓冲区,可能会使用某些方面(例如
std::codecvt
方面)。当通过调用虚拟函数
imbue()
更改区域设置时,如果流缓冲区使用该区域设置,您将能够拦截此更改并执行所需的任何同步


总之,该标准不能保证使用同一个流缓冲区使用并发线程进行读写。实际上,DS9k可能是唯一一个出现故障的系统,由于缓冲区指针位于共享缓存线中,两个线程可能最终有效地同步。

对于全双工,您需要两个缓冲区。如果对这两种接口都使用streambuf接口,以便将m连接到常用的ostream和istream接口,则整个画面如下所示:

这两个缓冲区显然是完全独立和对称的,因此我们可以忽略一侧,只关注单个缓冲区

此外,可以安全地假设只有两个线程:读取线程和写入线程。如果涉及更多线程,那么两个线程将同时读取或写入;这将导致不良的种族状况,因此毫无意义。我们可以假设用户将有某种机制,确保一次只有一个线程写入streambuf,同样,一次只有一个线程读取streambuf

在最一般的情况下,实际缓冲区存在多个连续内存块。每个put-and-get区域都完全位于一个这样的块中。只要它们在不同的内存块中,那么它们也是不相关的

每个get/put区域都有三个指针:一个指针指向区域的开始(eback/pbase),一个指针指向区域结束后的一个字节(egptr/epptr),一个指针指向区域中的当前位置(gptr/pptr)。从
std::streambuf
派生的类可以通过同名受保护的访问器(
eback()
pbase()
egptr()
epptr()
gptr()
pptr()
)直接访问这些指针注意,这里我们指的是一个streambuf的
eback()、egptr()和gptr()
,另一个streambuf的
pbase()、epptr()和pptr()
(见上图)

std::streambuf
具有访问或更改这六个指针的公共函数。它们是:

表,th,td{
边框:1px纯黑;
边界塌陷:塌陷;
}
th,td{
填充物:5px;
}

std::streambuf的公共成员函数
方法更改和/或访问
pubsetbuf()
调用派生最多的类的
setbuf()
pubseek