#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <queue>
#include <string>
#include <thread>
template <typename T>
class ThreadSafeQueue
{
public:
ThreadSafeQueue() { }
~ThreadSafeQueue() { }
bool
empty()
{
return(_queue.empty());
}
T
pop()
{
std::unique_lock<std::mutex> mlock(_mutex);
while (_queue.empty())
{
_cond.wait(mlock);
}
auto item = _queue.front();
_queue.pop();
return(item);
}
void
pop(T& item)
{
std::unique_lock<std::mutex> mlock(_mutex);
while (_queue.empty())
{
_cond.wait(mlock);
}
item = _queue.front();
_queue.pop();
}
void
push(const T& item)
{
std::unique_lock<std::mutex> mlock(_mutex);
_queue.push(item);
mlock.unlock();
_cond.notify_one();
}
void
push(T&& item)
{
std::unique_lock<std::mutex> mlock(_mutex);
_queue.push(std::move(item));
mlock.unlock();
_cond.notify_one();
}
private:
std::queue<T> _queue;
std::mutex _mutex;
std::condition_variable _cond;
};
int main() {
ThreadSafeQueue<std::string> q;
const int TOTAL = 100000;
const int N = 10; // must evenly divide TOTAL
std::atomic<int> count;
std::vector<std::thread> poppers;
for (int i = 0; i < N; ++i)
poppers.emplace_back([&]{ for(int i = 0; i < TOTAL / N; ++i) if (q.pop() == "foo") ++count; });
std::thread pusher([&]{ for(int i = 0; i < TOTAL; ++i) q.push("foo"); });
pusher.join();
for (auto& popper : poppers)
popper.join();
std::cout << "Queue is " << (q.empty() ? "" : "NOT ") << "empty" << std::endl;
std::cout << "Number of elements pushed = " << TOTAL << std::endl;
std::cout << "Number of elements popped = " << count << std::endl;
return 0;
}