OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-cogutil / opencog / util / pool.h

119 lines · c ref:
/*
 * util/pool.h ---
 *
 * Copyright (C) 2012 Poulin Holdings LLC
 *
 * Author: Linas Vepstas
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */


#ifndef _OPENCOG_UTIL_POOL_H
#define _OPENCOG_UTIL_POOL_H

#include <queue>
#include <mutex>
#include <condition_variable>

namespace opencog {
/** \addtogroup grp_cogutil
 *  @{
 */

//! Thread-safe blocking resource allocator.
/// If there are no resources to borrow, then the borrow() method will
/// block until one is given back.
///
/// This maintains a finite-sized pool of resources, which can be
/// borrowed and returned, much like a library book.  As long as the
/// pool is not empty, resources can be borrowed. If the pool is empty,
/// (there is nothing to be borrowed), then the borrowing thread will
/// block, until such time as the pool becomes non-empty.  When a
/// resource is returned, one of the blocked threads will be woken up,
/// and given the resource. Wakeups are in arbitrary order, and not
/// in any particular order (the thread waiting the longest is not
/// necessarily the one that gets woken up).
///
/// To start things off, resources need to be added to the pool.  This
/// can be done at any time at all: even after borrowers are lined up.
/// Resources can be permanently removed, simply by borrowing them and
/// never returning them.
///
/// A typical usage would be to create the pool in some master thread,
/// call `give_back()` N times to place N items in the pool, and then
/// let other threads start borrowing.  Alternately, other threads
/// can start borrowing right away; they'll block until someone puts
/// something into the pool.
///
/// Although you might think that boost::pool already does this, you'd
/// be wrong.  It would appear that the author of boost::pool did not
/// understand the problem that needed to be solved.
///
/// This is similar to concurrent_queue (also in this directory) but
/// with a simpler, less sophisticated API.  The main difference is that
/// this API uses names that make it clear that resources are being
/// borrowed, and returned, whereas the concurrent_queue has an API that
/// is geared towards the producer-consumer mode of thinking.
//
// This is implemented on top of std::queue, for no particular reason;
// pretty much any other container would do.
//
template<typename Resource>
class pool
{
    public:
        /// Fetch a resource from the pool. Block if the pool is empty.
        /// If blocked, this will unblock when a resource is put into
        /// the pool.
        Resource& borrow()
        {
            std::unique_lock<std::mutex> lock(mu);
            while (objs.empty()) {
                cond.wait(lock);
            }
            Resource& rv = objs.front();
            objs.pop();
            return rv;
        }

        /// Put a resource into the pool.  If the pool is empty, and
        /// other threads are blocked and waiting, this will release
        /// some other blocked thread.
        void give_back(const Resource& obj)
        {
            std::lock_guard<std::mutex> lock(mu);
            objs.push(obj);
            cond.notify_one();
        }

        size_t available()
        {
            return objs.size();
        }

    private:
        std::mutex mu;
        std::condition_variable cond;
        std::queue<Resource> objs;
};


/** @}*/
} // ~namespace opencog

#endif // _OPENCOG_UTIL_POOL_H