i2pd/libi2pd/Queue.h

134 lines
2.5 KiB
C
Raw Permalink Normal View History

/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
2013-12-10 17:00:13 +04:00
#ifndef QUEUE_H__
#define QUEUE_H__
#include <queue>
2015-01-23 06:00:41 +03:00
#include <vector>
2013-12-10 17:00:13 +04:00
#include <mutex>
#include <thread>
#include <condition_variable>
2014-04-23 20:49:02 +04:00
#include <functional>
2016-08-05 21:23:54 +03:00
#include <utility>
2013-12-10 17:00:13 +04:00
namespace i2p
{
namespace util
{
template<typename Element>
class Queue
2018-01-06 06:48:51 +03:00
{
2013-12-10 17:00:13 +04:00
public:
2015-06-16 20:14:33 +03:00
void Put (Element e)
2013-12-10 17:00:13 +04:00
{
std::unique_lock<std::mutex> l(m_QueueMutex);
2016-08-05 21:23:54 +03:00
m_Queue.push (std::move(e));
2013-12-10 17:00:13 +04:00
m_NonEmpty.notify_one ();
}
2017-01-16 23:58:05 +03:00
template<template<typename, typename...>class Container, typename... R>
void Put (const Container<Element, R...>& vec)
2015-01-23 06:00:41 +03:00
{
if (!vec.empty ())
2018-01-06 06:48:51 +03:00
{
std::unique_lock<std::mutex> l(m_QueueMutex);
2016-08-05 21:23:54 +03:00
for (const auto& it: vec)
2018-02-19 18:45:02 +03:00
m_Queue.push (std::move(it));
2015-01-23 06:00:41 +03:00
m_NonEmpty.notify_one ();
2018-01-06 06:48:51 +03:00
}
2015-01-23 06:00:41 +03:00
}
2018-01-06 06:48:51 +03:00
2015-06-16 20:14:33 +03:00
Element GetNext ()
2013-12-10 17:00:13 +04:00
{
std::unique_lock<std::mutex> l(m_QueueMutex);
2015-06-16 20:14:33 +03:00
auto el = GetNonThreadSafe ();
2013-12-10 17:00:13 +04:00
if (!el)
{
m_NonEmpty.wait (l);
el = GetNonThreadSafe ();
2018-01-06 06:48:51 +03:00
}
2013-12-10 17:00:13 +04:00
return el;
}
2015-06-16 20:14:33 +03:00
Element GetNextWithTimeout (int usec)
2013-12-10 17:00:13 +04:00
{
std::unique_lock<std::mutex> l(m_QueueMutex);
2015-06-16 20:14:33 +03:00
auto el = GetNonThreadSafe ();
2013-12-10 17:00:13 +04:00
if (!el)
{
m_NonEmpty.wait_for (l, std::chrono::milliseconds (usec));
el = GetNonThreadSafe ();
2018-01-06 06:48:51 +03:00
}
2013-12-10 17:00:13 +04:00
return el;
}
2014-01-11 05:21:38 +04:00
2014-04-23 20:17:14 +04:00
void Wait ()
{
std::unique_lock<std::mutex> l(m_QueueMutex);
m_NonEmpty.wait (l);
}
2014-01-11 05:21:38 +04:00
bool Wait (int sec, int usec)
{
std::unique_lock<std::mutex> l(m_QueueMutex);
return m_NonEmpty.wait_for (l, std::chrono::seconds (sec) + std::chrono::milliseconds (usec)) != std::cv_status::timeout;
}
2018-01-06 06:48:51 +03:00
bool IsEmpty ()
{
2014-01-11 05:21:38 +04:00
std::unique_lock<std::mutex> l(m_QueueMutex);
return m_Queue.empty ();
}
2015-02-04 00:45:19 +03:00
2018-01-06 06:48:51 +03:00
int GetSize ()
2015-02-04 00:45:19 +03:00
{
std::unique_lock<std::mutex> l(m_QueueMutex);
return m_Queue.size ();
2018-01-06 06:48:51 +03:00
}
2015-02-04 00:45:19 +03:00
2014-07-02 21:48:45 +04:00
void WakeUp () { m_NonEmpty.notify_all (); };
2013-12-10 17:00:13 +04:00
2015-06-16 20:14:33 +03:00
Element Get ()
2013-12-10 17:00:13 +04:00
{
std::unique_lock<std::mutex> l(m_QueueMutex);
return GetNonThreadSafe ();
2018-01-06 06:48:51 +03:00
}
2013-12-10 17:00:13 +04:00
2015-06-16 20:14:33 +03:00
Element Peek ()
2014-01-11 05:21:38 +04:00
{
std::unique_lock<std::mutex> l(m_QueueMutex);
return GetNonThreadSafe (true);
2018-01-06 06:48:51 +03:00
}
2013-12-10 17:00:13 +04:00
private:
2015-06-16 20:14:33 +03:00
Element GetNonThreadSafe (bool peek = false)
2013-12-10 17:00:13 +04:00
{
if (!m_Queue.empty ())
{
2015-06-16 20:14:33 +03:00
auto el = m_Queue.front ();
2014-01-11 05:21:38 +04:00
if (!peek)
m_Queue.pop ();
2013-12-10 17:00:13 +04:00
return el;
2018-01-06 06:48:51 +03:00
}
2013-12-10 17:00:13 +04:00
return nullptr;
2018-01-06 06:48:51 +03:00
}
2013-12-10 17:00:13 +04:00
private:
2015-06-16 20:14:33 +03:00
std::queue<Element> m_Queue;
2013-12-10 17:00:13 +04:00
std::mutex m_QueueMutex;
std::condition_variable m_NonEmpty;
2018-01-06 06:48:51 +03:00
};
}
}
2013-12-10 17:00:13 +04:00
#endif