How to block on reading a c++ stringstream to wait for data
Asked Answered
B

2

6

So, I've been trying to figure out, how to wait for data from a C++ stringstream (for instance), without being constantly checking if data is there, which is quite CPU consuming.

I'm perfectly able to read, for instance, from a serial device, and lock the process while no data arrives, but unfortunately I haven't been able to figure how to do that with C++ streams.

I'm sure I'm missing something, since cin does exactly that, i.e., waits for the return key to step out from istream reading, but how does it do it?

Thanks in advance for any light on the subject.

Boogie answered 10/9, 2012 at 11:54 Comment(9)
Have you tried e.g. std::getline?Inconsequent
All streams work the same. If you create a stream from blocking file descriptor, it will be blocking (just like cin, it's also created that way). So what have you tried and does not work for you?Dominate
@JoachimPileborg Yes I did! Does it lock for you?Boogie
@JanHudec All streams do not work the same. Or rather, all streambufs don't work the same. (The various streams just forward to a streambuf.) In particular, filebuf has the notion of open, and depends on the OS to tell it when there are no more characters to be read. This concept is absent in stringbuf. So it can't wait for the "output" side to be closed to declare end of file on the input.Pelagian
@JanHudec It's quite simple, each time it reaches eof, it just quits whatever method I'm using to read the stream (getline, read...). So, but you're saying I should be able to create a C++ stream based on a descriptor without using any external libs?Boogie
@cvicente: Each time it reaches eof, it just quits. That's how it's designed. But when reading blocking file descriptor, the underlying function will simply block, not reach eof. Can you please mention specific functions you are using to create the stream? Or better yet show a code sample?Dominate
@JamesKanze: To be more specific, cin, cout, and fistream and fostream all do work the same and so do their streambufs. They work the same, because the underlying system calls (or rather ANSI C library calls that file streams normally work on) are the same for those two cases. And as long as a device can be used with ANSI C functions (on POSIX, anything can, on Windows you are out of luck and have to write the streambuf yourself or get one somewhere), it can be used and will work out of the box.Dominate
@JanHudec cin, cout, ifstream and ofstream work the same, because they all use filebuf. The OP asks about stringstream, which uses a stringbuf. A lot of the time, of course, you'll be using some other streambuf. (And I've not noticed a great deal of difference between Unix and Windows in this respect. In both, filebuf are usually normally named files, but you can also open them on special devices which behave differently.)Pelagian
@JamesKanze: Ok, right. I ignored the stringstream mention, because device was mentioned and stringstream wouldn't be used for reading device.Dominate
L
3

Streams obtain data from an std::streambuf. For the case of std::cin it calls the system's read() function (or equivalent) which blocks until data is handed over from the operating system. The console normally sends complete lines. String streams have no concept of getting new data, i.e., they would fail when having reached the end of the current data. There isn't a concept of blocking.

You didn't quite say what you are doing but from the sounds of it try to communicate data between two threads: one reading and possibly blocking until data is available and one filling in more data. You could create a corresponding stream buffer quite easily: std::streambuf::underflow() would wait() on a condition variable if there is no data. std::streambuf::overflow() would set up the buffer appropriately and signal the condition variable. Obviously, there is some need of synchronization necessary. Most of the reading and writing isn't doing any synchronization, though. This effectively means that you will need two separate buffers for input and output and need to copy the data in std::streambuf::underflow().

Longheaded answered 10/9, 2012 at 12:13 Comment(2)
I considered this. But wouldn't a std::deque using the basic binary data be more appropriate? The whole point about using threads (instead of separate processes) is that you don't have to marshal the data. (Alternatively, if I did want to use streams here, I think I'd go with two separate streambuf types, which collaborate.)Pelagian
From the sounds of it the original request wanted to read from a stream and, presumably, write to it. If the logic to interact with a stream alread exists it may be reasonable to use streams to interact. Normally, I would communicate with something looking like a queue, possibly implemented in terms of a std::deque.Halliburton
P
1

You can't. The only way std::stringstream can know that there isn't any further data is that there isn't any data in the stream.

It's an interesting thought, however. << on an std::stringstream only returns true if the write side has been closed. The only problem with the idea is that std::stringstream doesn't have any idea of open or closed.

The real question, however, is what you're trying to achieve. std::stringstream operates in process, and in that case, there's really no need for formatting (which is the abstraction of the iostreams in general). Just stuff the raw objects in an std::deque. The only time you should need to worry about formatting is when communicating with the exterior. std::istringstream is very useful, for example, when you're getting the string from std::getline on a file, or from some other source. Similarly, std::ostringstream is useful when formatting data for some external source which requires a string of some sort. But I've never found a use for std::stringstream; it's there more for reasons of orthogonality, I think.

Pelagian answered 10/9, 2012 at 12:13 Comment(6)
Sure you can. If the streambuf::uflow blocks, the stream blocks. End of story.Dominate
@JanHudec The implementation of stringbuf::uflow doesn't block. End of story.Pelagian
Right. The question is really mixed up though; the answer probably should be "whatever you are trying to do, it probably does not involve stringstreams".Dominate
@JanHudec That's more or less my conclusion too. (I don't think I've ever uses std::stringstream.)Pelagian
I use stringstreams often. They are useful for formatting and parsing. But not for passing data.Dominate
@JanHudec istringstream is useful for parsing, and ostringstream for formatting. I use those two often. But I've never found a use for the bi-directional stringstream; there's generally no point of formatting something only to reparse it in the same process.Pelagian

© 2022 - 2024 — McMap. All rights reserved.