// // Simple Producer-Consumer application // that uses the C++11 STL-threads and condition variables. // Producer reads a string from console, puts it into the buffer // and notifies consumer about non-empty buffer. // Consumer takes the string from the buffer, // inverts the string and prints it. // Then it notifies producer about the free console, // so that producer can read the next string. // // Synchronization uses 2 conditional variables and 2 mutexes: // bufferCondition, consoleCondition, // bufferMutex, consoleMutex. // #include #include #include #include #include #include #include #include static std::mutex bufferMutex; static std::mutex consoleMutex; static std::condition_variable bufferCondition; static std::condition_variable consoleCondition; static std::deque buffer; static bool consoleFree = true; // Produce can use the console static bool finish = false; // Terminate the program void runProducer(); // Thread function for producer void runConsumer(); // Thread function for consumer std::string invert(const std::string); int main() { std::thread producer(runProducer); std::thread consumer(runConsumer); producer.join(); consumer.join(); return 0; } void runProducer() { while (!finish) { std::string s; { std::unique_lock consoleLock(consoleMutex); while (!consoleFree) { // Wait for console to be free consoleCondition.wait(consoleLock); } // Input a line std::getline(std::cin, s); consoleFree = false; // Pass the console to consumer } { std::lock_guard bufferLock(bufferMutex); if (s == "" || s == "q") { finish = true; } else { // Add a line to the buffer buffer.push_back(s); // Pass the string to consumer } } bufferCondition.notify_one(); // Notify the consumer about } // new string in the buffer } void runConsumer() { while (true) { std::string s; { std::unique_lock bufferLock(bufferMutex); while (!finish && buffer.empty()) { // Wait for a string bufferCondition.wait(bufferLock); } if (finish) { break; // Terminate the thread } assert(!buffer.empty()); s = buffer.front(); // Take a string from the buffer buffer.pop_front(); } std::string inverted = invert(s); { std::lock_guard consoleLock(consoleMutex); std::cout << inverted << std::endl; consoleFree = true; // Relese the console } consoleCondition.notify_one(); // Notify the producer } // about free console } std::string invert(const std::string s) { size_t len = s.size(); std::vector inverted(len + 1); for (size_t i = 0; i < len; ++i) { inverted[len - 1 - i] = s[i]; } inverted[len] = 0; return std::string(inverted.data()); }