-
-
Save vmrob/ff20420a20c59b5a98a1 to your computer and use it in GitHub Desktop.
#include <iostream> | |
#include <chrono> | |
#include <future> | |
#include <string> | |
std::string GetLineFromCin() { | |
std::string line; | |
std::getline(std::cin, line); | |
return line; | |
} | |
int main() { | |
auto future = std::async(std::launch::async, GetLineFromCin); | |
while (true) { | |
if (future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { | |
auto line = future.get(); | |
// Set a new line. Subtle race condition between the previous line | |
// and this. Some lines could be missed. To aleviate, you need an | |
// io-only thread. I'll give an example of that as well. | |
future = std::async(std::launch::async, GetLineFromCin); | |
std::cout << "you wrote " << line << std::endl; | |
} | |
std::cout << "waiting..." << std::endl; | |
std::this_thread::sleep_for(std::chrono::seconds(1)); | |
} | |
} |
@vmrob "you need an io-only thread. I'll give an example of that as well." Is the example the future = std::async(std::launch::async, GetLineFromCin); or did you intend to add something else?
Well hello everyone! I'm not sure why I wrote this so long ago, but I have a feeling I wrote it intending to show someone a thing and looking at it now, I'm not sure what I was thinking. Since it looks like at least one person has created a stack overflow post leading people here, it's probably worth revisiting.
Today, if I were writing this, it would be probably use a separate thread for io–it's certainly a simpler. It still has efficiency problems related to memory churn, and without any bounding on queue sizes, I think it's sort of flawed, but I guess the context of why this would be desired is pretty necessary to come up with a better solution.
#include <mutex>
#include <deque>
#include <thread>
#include <iostream>
#include <condition_variable>
#include <string>
#include <chrono>
int main() {
std::condition_variable cv;
std::mutex mutex;
std::deque<std::string> lines; // protected by m
// thread to read from stdin
std::thread io{[&]{
std::string tmp;
while (true) {
std::getline(std::cin, tmp);
std::lock_guard lock{mutex};
lines.push_back(std::move(tmp));
cv.notify_one();
}
}};
// the nonblocking thread
std::deque<std::string> toProcess;
while (true) {
{
// critical section
std::unique_lock lock{mutex};
if (cv.wait_for(lock, std::chrono::seconds(0), [&]{ return !lines.empty(); })) {
// get a new batch of lines to process
std::swap(lines, toProcess);
}
}
if (!toProcess.empty()) {
std::cout << "processing new lines..." << std::endl;
for (auto&& line : toProcess) {
// process lines received by io thread
std::cout << line << std::endl;
}
toProcess.clear();
}
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "waiting 1s..." << std::endl;
}
}
@vmrob I like this approach. A small notice only: instead of calling sleep at the end of the while loop, why don't you put std::chrono::seconds(1) in the wait_for instead?
@vmrob I like this approach. A small notice only: instead of calling sleep at the end of the while loop, why don't you put std::chrono::seconds(1) in the wait_for instead?
i think he wants mutex (critical condition) to be over as fast as possible, so he doesn't block the io thread
@cyberstealth1024, I think you're talking about something like
std::this_thread::yield()
. But if you use something like 1ms or yield() you will be watchingwaiting...
message appear very frequently