Reputation: 22376
I'm sending streaming data between threads using std::iostreams
but struggling to extract the data, here's a contrived example:
#include <sstream>
#include <iostream>
#include <thread>
#include <chrono>
#include <atomic>
#include <mutex>
using namespace std::chrono_literals;
int main()
{
auto stream = std::stringstream{};
auto stop = std::atomic_bool{false};
auto mtx = std::mutex{};
auto thread = std::thread{[&]() {
while(!stop) {
auto lock = std::lock_guard{mtx};
if (stream.peek() != decltype(stream)::traits_type::eof()) {
auto str = std::string{};
stream >> str;
std::cout << str;
}
}
}};
{
// Make sure thread is running before sending data
std::this_thread::sleep_for(100ms);
{
auto lock = std::lock_guard{mtx};
stream << "hello" << std::endl;
}
// Give the thread a chance to receive it
std::this_thread::sleep_for(100ms);
}
stop = true;
thread.join();
return EXIT_SUCCESS;
}
Running it, yields no output - debugging shows that stream.peek()
is always EOF
. I must be doing something wrong but I can't see it!
Upvotes: 0
Views: 452
Reputation: 38209
Problem is caused by fact that you are reading data before there is anything to read (it was written).
When you have tried to read data from empty stream error flags are getting set and then any following read/write operation on such stream are not executed until error flags are cleared.
You need something what will ensure that reading will happen after writing. std::condition_variable
can do that.
int main()
{
auto stream = std::stringstream{};
auto mtx = std::mutex{};
auto hasData = std::condition_variable{};
auto readingStarted = std::condition_variable{};
auto thread = std::thread{[&]() {
std::unique_lock<std::mutex> lock{mtx};
readingStarted.notify_one();
hasData.wait(lock);
auto str = std::string{};
stream >> str;
std::cout << str;
}};
{
auto lock = std::unique_lock{mtx};
readingStarted.wait(lock);
stream << "hello" << std::endl;
hasData.notify_one();
}
thread.join();
return EXIT_SUCCESS;
}
Upvotes: 2