2

I have been trying to understand buffering as much as possible in C++ (it's amazingly confusing) for a Serial I/O program I'm writing. I originally wasn't flushing my output commands (due to ignorance), so instead I looked up here (How to disable buffering on a stream?), and it said to do it through my_fstream.rdbuf()->pubsetbuf(0,0) before any I/O operation has happened. This seemed to improve my performance, but not fix it entirely... I kept looking for answers and found these two questions: Unbuffered I/O is not working, Unbuffered output with cout, which both say to use my_fstream.setf(std::ios::unitbuf); instead. This worked much better, but neither of those answers explained why it works better than my_fstream.rdbuf()->pubsetbuf(0,0).

Shouldn't they be doing the same thing? Can someone explain to me the difference?

Here's the code I'm testing this on (the device replies to an input of "Start" when it receives it by sending "Ready\r\n" back):

int main(){
    std::fstream my_file;
    my_file.rdbuf()->pubsetbuf(0, 0);
    // my_file.setf(std::ios::unitbuf);  // Uncomment this line for testing both cases
    my_file.open("/dev/cu.usbmodem14201");
    my_file << "Start";
    std::this_thread::sleep_for(std::chrono::seconds(10));
}

By the time I reach my sleep, there is no output yet (I need to wait the 10 seconds to see it) unless I uncomment the commented line.

I can confirm messages are received by running a separate python program:

with open("/dev/cu.usbmodem14201", "rb") as f:
    for line in f:
        print(line)
polortiz40
  • 391
  • 4
  • 13
  • unitbuf desn't disable buffering, it just causes the stream to be flushed after every output operation – john May 25 '20 at 21:15
  • @Ron, I've noticed that pubsetbuf(0, 0) does have some effect. I can't quite accurately describe what it is. But in my actual application, commenting it out produces different behavior. – polortiz40 May 25 '20 at 21:18
  • @john Interesting, I didn't know. Doesn't that implicitly mean there is no buffer? why would you store in a buffer characters that have already been flushed? Although I'm more interested to understand why pubsetbuf(0, 0) isn't flushing after every output operation if there is no buffer to store it's info on. – polortiz40 May 25 '20 at 21:21
  • @polortiz40 "*why pubsetbuf(0, 0) isn't flushing after every output operation if there is no buffer to store it's info on*" - It should be, according to [`std::basic_filebuf::setbuf`](https://en.cppreference.com/w/cpp/io/basic_filebuf/setbuf): "*If s is a null pointer and n is zero, **the filebuf becomes unbuffered for output, meaning pbase() and pptr() are null and any output is immediately sent to file**.*" – Remy Lebeau May 26 '20 at 01:29
  • 2
    Not everything is under the control of C++. Just because C++ doesn't have a buffer doesn't mean that the OS or the runtime don't. I guess the explanation here is that in pubsetbuf(0,0) case there is no C++ buffer and therefore no flushing, but there is still some system buffer so you don't see output immediately. But in the unitbuf case there is flushing and that flushing affects any system buffers too. If correct that would be a kind of wonky implementation. You need to dig down into the code for a definitive answer. – john May 26 '20 at 05:30
  • @RemyLebeau Yeah that's what I was confused about. Perhaps I shouldn't claim that pubsetbuf doesn't "flush". I should say that the command doesn't reach my device, which I thought of as equivalent, but john is pointing out C++ flushing and my command reaching the device are not necessarily the same thing due to an intermediate buffer in the OS. – polortiz40 May 26 '20 at 05:48

0 Answers0