📄 syn_4687.htm
字号:
<HTML><HEAD><TITLE>2.10 Synchronizing Streams</TITLE></HEAD><BODY><A HREF="ug2.htm"><IMG SRC="images/banner.gif"></A><BR><A HREF="str_0182.htm"><IMG SRC="images/prev.gif"></A><A HREF="booktoc2.htm"><IMG SRC="images/toc.gif"></A><A HREF="str_5412.htm"><IMG SRC="images/next.gif"></A><BR><STRONG>Click on the banner to return to the user guide home page.</STRONG><H2>2.10 Synchronizing Streams</H2><P>In the previous section, we saw how streams can share stream buffers. In this section, we will see that streams can also share a file, as when streams in different processes exchange data through a file. Figure 20 graphically illustrates how streams share files:</P><H4>Figure 20. Streams sharing a file</H4><BR><IMG SRC="images/image37.gif"><P>Because streams use a buffer, the content of the file might be different from the content of the buffer that is supposed to reflect the file's content. When data is extracted through a file stream, a certain part of the file's content is read into the buffer; subsequent extractions access the buffer instead of the file. Once the file content is modified, the buffer content becomes obsolete. Similarly, when data is written through a file stream, the output is stored in the buffer and not written to the file. The file is accessed only when the buffer is full. For this reason, output from one stream will not be immediately available to the other stream.</P><A NAME="2.10.1"><H3>2.10.1 Explicit Synchronization</H3></A><P>You can force the stream to empty its buffer into an output file, or to refill its buffer from an input file. This is done through the stream buffer's function <SAMP>pubsync()</SAMP>. Typically, you will call <SAMP>pubsync()</SAMP> indirectly through functions of the stream layer. Input streams and output streams have different member functions that implicitly call <SAMP>pubsync()</SAMP>.</P><A NAME="2.10.1.1"><H4>2.10.1.1 Output Streams</H4></A><P>Output streams have a <SAMP>flush()</SAMP> function that writes the buffer content to the file. In case of failure, <SAMP>badbit</SAMP> will be set or an exception thrown, depending on the exception mask.</P><PRE>ofstream ofstr("/tmp/fil");ofstr << "Hello "; \\1ofstr << "World!\n";ofstr.flush(); \\2</PRE><TABLE CELLPADDING="3"><TR VALIGN="top"><TD>//1</TD><TD>The attempt to extract anything from the file <SAMP>/tmp/fil</SAMP> after this insertion will probably fail, because the string <SAMP>"Hello "</SAMP> is buffered and not yet written to the external file.</TD></TR><TR VALIGN="top"><TD>//2</TD><TD>After the call to <SAMP>flush()</SAMP>, however, the file will contain "<SAMP>Hello World!\n"</SAMP>. (Incidentally, the call to <SAMP>ostr.flush()</SAMP> can be replaced by the <SAMP>flush</SAMP> manipulator; i.e., <SAMP>ostr << flush;</SAMP>)</TD></TR></TABLE><P>Keep in mind that flushing is a time-consuming operation. The function <SAMP>flush()</SAMP>not only writes the buffer content to the file; it may also reread the buffer in order to maintain the current file position. For the sake of performance, you should avoid inadvertent flushing, as when the <SAMP>endl</SAMP> manipulator calls <SAMP>flush()</SAMP> on inserting the end-of-line character. (See <A HREF="man_6665.htm#2.8.1.2">Section 2.8.1.2</A>.)</P><A NAME="2.10.1.2"><H4>2.10.1.2 Input Streams</H4></A><P>Input streams have a <SAMP>sync()</SAMP> function. It forces the stream to access the external device and refill its buffer, beginning with the current file position. The example below demonstrates the principle theoretically. In real-life, however, the two streams would belong to two separate processes and could use the shared file to communicate.</FN><PRE>ofstream ofstr("/tmp/fil");ifstream ifstr("/tmp/fil");string s;ofstr << "Hello "ofstream::pos_type p = ofstr.tellp();ofstr << "World!\n" << flush;ifstr >> s; \\1 ofstr.seekp(p);ofstr << "Peter!" << flush; \\2ifstr >> s; \\3ofstr << " Happy Birthday!\n" << flush; \\4ifstr >> s; \\5ifstr.sync(); \\6ifstr >> s;</PRE><TABLE CELLPADDING="3"><TR VALIGN="top"><TD>//1</TD><TD>Here the input stream extracts the first string from the shared file. In doing so, the input stream fills its buffer. It reads as many characters from the external file as needed to fill the internal buffer. For this reason, the number of characters to be extracted from the file is implementation-specific; it depends on the size of the internal stream buffer. </TD></TR><TR VALIGN="top"><TD>//2</TD><TD>The output stream overwrites part of the file content. Now the file content and the content of the input stream's buffer are inconsistent. The file contains <SAMP>"Hello Peter!"</SAMP>; the input stream's buffer still contains <SAMP>"Hello World!"</SAMP>.</TD></TR><TR VALIGN="top"><TD>//3</TD><TD>This extraction takes the string <SAMP>"World!"</SAMP> from the buffer instead of yielding <SAMP>"Peter!"</SAMP>, which is the current file content.</TD></TR><TR VALIGN="top"><TD>//4</TD><TD>More characters are appended to the external file. The file now contains <SAMP>"Hello Peter! Happy Birthday!"</SAMP>, whereas the input stream's buffer is still unchanged.</TD></TR><TR VALIGN="top"><TD>//5</TD><TD>This extraction yields nothing. The input stream filled its buffer with the entire content of the file because the file is so small in our toy example. Subsequent extractions made the input stream hit the end of its buffer, which is regarded as the end of the file as well. The extraction results in <SAMP>eofbit</SAMP> set, and nothing will be extracted. There is no reason to ever access the external file again.</TD></TR><TR VALIGN="top"><TD>//6</TD><TD>A call to <SAMP>sync()</SAMP> eventually forces the input stream to refill the buffer from the external device, beginning with the current file position. After the synchronization, the input stream's buffer will contain <SAMP>"Happy Birthday!\n"</SAMP>. The next extraction will yield <SAMP>"Happy"</SAMP>.<BR><BR>As the draft specifies the behavior of <SAMP>sync()</SAMP> as implementation-defined, you can alternatively try repositioning the input stream to the current position instead; i.e.,<SAMP> istr.seekg(ios_base::cur);</SAMP></TD></TR></TABLE><HR><STRONG><P><I>Please note: </I>If you have to synchronize several streams that share a file, it is advisable to call the <SAMP>sync()</SAMP> function after each output operation and before each input operation.</P></STRONG><HR><A NAME="2.10.2"><H3>2.10.2 Implicit Synchronization Using the unitbuf Format Flag</H3></A><P>You can achieve a kind of automatic synchronization for output files by using the format flag <SAMP>ios_base::unitbuf</SAMP>. It causes an output stream to flush its buffer after each output operation as follows:</P><PRE>ofstream ostr("/tmp/fil");ifstream istr("/tmp/fil");ostr << unitbuf; \\1while (some_condition){ ostr << "_ some output_"; \\2 // process the output istr >> s; // _}</PRE><TABLE CELLPADDING="3"><TR VALIGN="top"><TD>//1</TD><TD>Set the <SAMP>unitbuf</SAMP> format flag.</TD></TR><TR VALIGN="top"><TD>//2</TD><TD>After each insertion into the shared file <SAMP>/tmp/fil,</SAMP> the buffer is automatically flushed, and the output is available to other streams that read from the same file.</TD></TR></TABLE><P>Since it is not overly efficient to flush after every single token that is inserted, you might consider switching off the <SAMP>unitbuf</SAMP> flag for a lengthy output that is not supposed to be read partially.</P><PRE>ostr.unsetf(ios_base::unitbuf); \\1ostr << " _ some lengthy and complicated output _";ostr.flush().setf(ios_base::unitbuf); \\2</PRE><TABLE CELLPADDING="3"><TR VALIGN="top"><TD>//1</TD><TD>Switch off the <SAMP>unitbuf</SAMP> flag. Alternatively, using manipulators, you can say <SAMP>ostr << nounitbuf;</SAMP></TD></TR><TR VALIGN="top"><TD>//2</TD><TD>Flush the buffer and switch on the <SAMP>unitbuf</SAMP> flag again. Alternatively, you can say <SAMP>ostr << flush << unitbuf;</SAMP></TD></TR></TABLE><A NAME="2.10.3"><H3>2.10.3 Implicit Synchronization by Tying Streams</H3></A><P>Another mechanism for automatic synchronization in certain cases is tying a stream to an output stream, as demonstrated in the code below. All input or output operations flush the tied stream's buffer before they perform the actual operation.</P><PRE>ofstream ostr("/tmp/fil");ifstream istr("/tmp/fil");ostream* old_tie = istr.tie(&ostr); //1 while (some_condition){ ostr << " some output "; string s; while (istr >> s) //2 // process input ;}istr.tie(old_tie); //3</PRE><TABLE CELLPADDING="3"><TR VALIGN="top"><TD>//1</TD><TD>The input stream <SAMP>istr</SAMP> is tied to the output stream <SAMP>ostr</SAMP>. The <SAMP>tie()</SAMP> function returns a pointer to the previously tied output stream, or zero if no output stream is tied.</TD></TR><TR VALIGN="top"><TD>//2</TD><TD>Before any input is done, the tied output stream's buffer is flushed so that the result of previous output operations to <SAMP>ostr</SAMP> is available in the external file <SAMP>/tmp/fil</SAMP>.</TD></TR><TR VALIGN="top"><TD>//3</TD><TD>The previous tie is restored.</TD></TR></TABLE><A NAME="2.10.4"><H3>2.10.4 Synchronizing the Predefined Standard Streams</H3></A><P>The predefined streams <SAMP>cin</SAMP>, <SAMP>cout</SAMP>, <SAMP>cerr</SAMP>, and <SAMP>clog</SAMP> are examples of synchronized streams:</P><UL><LI><P><SAMP>cin</SAMP> is tied to <SAMP>cout</SAMP>; i.e., before each input operation on <SAMP>cin</SAMP>, the output stream <SAMP>cout</SAMP> is forced to flush its buffer.</P></LI><LI><P><SAMP>cerr</SAMP> is synchronized using the <SAMP>unitbuf</SAMP> format flag; i.e., after each output to <SAMP>cerr,</SAMP> its buffer is flushed.</P></LI><LI><P><SAMP>clog</SAMP> is connected to the same output channel and thus behaves like <SAMP>cerr</SAMP>, except that it is not synchronized with any of the other standard streams; i.e., it does not have the <SAMP>unitbuf</SAMP> flag set.</P></LI></UL><A NAME="2.10.5"><H3>2.10.5 Synchronization with the C Standard I/O</H3></A><P>The predefined C++ streams <SAMP>cin</SAMP>, <SAMP>cout</SAMP>, <SAMP>cerr</SAMP>, and <SAMP>clog</SAMP> are associated with the standard C files <SAMP>stdin</SAMP>, <SAMP>stdout</SAMP>, and <SAMP>stderr,</SAMP> as we saw in <A HREF="for_5394.htm#2.3.1">Section 2.3.1</A>. This means that insertions into <SAMP>cout</SAMP>, for instance, go to the same file as output to <SAMP>stdout</SAMP>. By default, input and output to the predefined streams is synchronized with read or write operations on the standard C files. The effect is that input and output operations are executed in the order of invocation, independently of whether the operations used the predefined C++ streams or the standard C files.</P><P>This synchronization is time-consuming and thus might not be desirable in all situations. You can switch it off by calling:</P><PRE>sync_with_stdio(false);</PRE><P>After such a call, the predefined streams operate independently of the C standard files, with possible performance improvements in your C++ stream operations. However, you should call <SAMP>sync_with_stdio()</SAMP> prior to any input or output operation on the predefined streams, because otherwise the effect of calling <SAMP>sync_with_stdio()</SAMP> will be implementation-defined.</P><HR><A HREF="str_0182.htm"><IMG SRC="images/prev.gif"></A> <A HREF="booktoc2.htm"><IMG SRC="images/toc.gif"></A><A HREF="str_5412.htm"><IMG SRC="images/next.gif"></A><P>©Copyright 1996, Rogue Wave Software, Inc.</P></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -