1

I started two threads, thread t1 is waiting for input via cin. Can I put something like an EOF bit to cin from thread t2to stop cin from reading? I tried '\n' and ios::eofbit. Both did not work.

#include <thread>
#include <iostream>
#include <string>
#include <condition_variable>

std::condition_variable cv;

void Foo()
{
    std::string sFoo;
    std::cin >> sFoo;
    // Do stuff with sFoo
}

void Bar()
{
    // Do stuff
    // If a condition is fullfilled I don't need the input in Foo anymore and so I want to cancel cin.

    std::cin.setstate(std::ios::setstate(std::ios::eofbit); // Does not work
    std::cin.putback('\n'); // Does not work

    // maybe something similar like these above
}

int main()
{
    std::thread t1(Foo);
    std::thread t2(Bar);
}
Rama
  • 3,222
  • 2
  • 11
  • 26
mario.b
  • 165
  • 1
  • 12
  • @KerrekSB There is no cin.close() function... Please correct me if I'm wrong – mario.b Feb 22 '17 at 15:41
  • You're right, never mind :-S – Kerrek SB Feb 22 '17 at 15:42
  • @Mario Try `::close( STDIN_FILENO );` or `::fclose( stdin );` or even `::close( 0 );`. See http://stackoverflow.com/questions/288062/is-close-fclose-on-stdin-guaranteed-to-be-correct It's a bit drastic... – Andrew Henle Feb 22 '17 at 15:42
  • You can build logic such that if thread1 reads something specific then it can exit. Now thread2 can `putback` that something specific in order for thread1 to exit. see this example(http://www.cplusplus.com/reference/istream/istream/putback/) – sameerkn Feb 23 '17 at 09:28
  • @sameerkn Then there is still the problem that the user has to push the enter key to close cin reading. – mario.b Feb 23 '17 at 11:45
  • If you simply want to cancel `cin` in `foo` from `bar` then simply use a `bool read_valid = true;` variable which will decide whether to use `cin` in `foo`. `read_valid` will be read-only in `foo` and write-only in `bar`. Inside `bar` when the condition is satisfied then simply make `read_valid = false`. – sameerkn Feb 23 '17 at 11:54

1 Answers1

0

I don't think there is a standard non-blocking read from istream or a means to interrupt a thread waiting for input. You might try to look at boost asio or boost iostreams - perhaps they have this functionality.

You could use select/poll on POSIX systems or their counterparts on other systems to check if any data is available, or use some form of interruptive read - API is system-dependent also.

Below is a dirty solution that works - you end up with a leaked thread that will forever wait on stdin, but it does what you want.

#include <thread>
#include <iostream>
#include <string>
#include <condition_variable>
#include <chrono>
#include <mutex>
#include <queue>

std::mutex m;
bool dataEnd = false;
std::queue<std::string> data;
std::condition_variable sAvail;

void Reader() {
    while (std::cin) {
        auto s = std::string();
        std::cin >> s;

        auto lock = std::unique_lock<std::mutex>(m);
        data.push(std::move(s));
        sAvail.notify_all();
    }
}

void Foo() {
    for (;;) {
        auto lock = std::unique_lock<std::mutex>(m);
        if (data.empty()) {
            sAvail.wait(lock);
            if (dataEnd) {
                std::cerr << "No more data!\n";
                break;
            }
        }

        if (!data.empty()) {
            auto s = std::move(data.front());
            data.pop();
            std::cerr << "Got " << s << '\n';
        }
    }
}

void Bar(std::thread& reader) {
    // Do stuff
    // If a condition is fullfilled I don't need the input in Foo anymore and so I want to cancel cin.

    {
        auto lock = std::unique_lock<std::mutex>(m);
        dataEnd = true;
        sAvail.notify_all();
        reader.detach();
    }

    // maybe something similar like these above
}

int main() {
    std::thread r(Reader);
    std::thread t1(Foo);
    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    std::thread t2(Bar, std::ref(r));

    t1.join();
    t2.join();
}
mikosz
  • 393
  • 1
  • 8