mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-10-31 07:25:22 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			213 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			213 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| Minetest
 | |
| Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
 | |
| 
 | |
| This program is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU Lesser General Public License as published by
 | |
| the Free Software Foundation; either version 2.1 of the License, or
 | |
| (at your option) any later version.
 | |
| 
 | |
| 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 Lesser General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU Lesser General Public License along
 | |
| with this program; if not, write to the Free Software Foundation, Inc.,
 | |
| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | |
| */
 | |
| 
 | |
| #ifndef UTIL_THREAD_HEADER
 | |
| #define UTIL_THREAD_HEADER
 | |
| 
 | |
| #include "../irrlichttypes.h"
 | |
| #include "../jthread/jthread.h"
 | |
| #include "../jthread/jmutex.h"
 | |
| #include "../jthread/jmutexautolock.h"
 | |
| #include "porting.h"
 | |
| 
 | |
| template<typename T>
 | |
| class MutexedVariable
 | |
| {
 | |
| public:
 | |
| 	MutexedVariable(T value):
 | |
| 		m_value(value)
 | |
| 	{
 | |
| 	}
 | |
| 
 | |
| 	T get()
 | |
| 	{
 | |
| 		JMutexAutoLock lock(m_mutex);
 | |
| 		return m_value;
 | |
| 	}
 | |
| 
 | |
| 	void set(T value)
 | |
| 	{
 | |
| 		JMutexAutoLock lock(m_mutex);
 | |
| 		m_value = value;
 | |
| 	}
 | |
| 	
 | |
| 	// You'll want to grab this in a SharedPtr
 | |
| 	JMutexAutoLock * getLock()
 | |
| 	{
 | |
| 		return new JMutexAutoLock(m_mutex);
 | |
| 	}
 | |
| 	
 | |
| 	// You pretty surely want to grab the lock when accessing this
 | |
| 	T m_value;
 | |
| 
 | |
| private:
 | |
| 	JMutex m_mutex;
 | |
| };
 | |
| 
 | |
| /*
 | |
| 	A single worker thread - multiple client threads queue framework.
 | |
| */
 | |
| template<typename Key, typename T, typename Caller, typename CallerData>
 | |
| class GetResult
 | |
| {
 | |
| public:
 | |
| 	Key key;
 | |
| 	T item;
 | |
| 	std::pair<Caller, CallerData> caller;
 | |
| };
 | |
| 
 | |
| template<typename Key, typename T, typename Caller, typename CallerData>
 | |
| class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
 | |
| {
 | |
| };
 | |
| 
 | |
| template<typename Caller, typename Data, typename Key, typename T>
 | |
| class CallerInfo
 | |
| {
 | |
| public:
 | |
| 	Caller caller;
 | |
| 	Data data;
 | |
| 	ResultQueue< Key, T, Caller, Data>* dest;
 | |
| };
 | |
| 
 | |
| template<typename Key, typename T, typename Caller, typename CallerData>
 | |
| class GetRequest
 | |
| {
 | |
| public:
 | |
| 	GetRequest()
 | |
| 	{
 | |
| 	}
 | |
| 	GetRequest(Key a_key)
 | |
| 	{
 | |
| 		key = a_key;
 | |
| 	}
 | |
| 	~GetRequest()
 | |
| 	{
 | |
| 	}
 | |
| 	
 | |
| 	Key key;
 | |
| 	std::list<CallerInfo<Caller, CallerData, Key, T> > callers;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * Notes for RequestQueue usage
 | |
|  * @param Key unique key to identify a request for a specific resource
 | |
|  * @param T ?
 | |
|  * @param Caller unique id of calling thread
 | |
|  * @param CallerData data passed back to caller
 | |
|  */
 | |
| template<typename Key, typename T, typename Caller, typename CallerData>
 | |
| class RequestQueue
 | |
| {
 | |
| public:
 | |
| 	bool empty()
 | |
| 	{
 | |
| 		return m_queue.empty();
 | |
| 	}
 | |
| 
 | |
| 	void add(Key key, Caller caller, CallerData callerdata,
 | |
| 			ResultQueue<Key, T, Caller, CallerData> *dest)
 | |
| 	{
 | |
| 		{
 | |
| 			JMutexAutoLock lock(m_queue.getMutex());
 | |
| 
 | |
| 			/*
 | |
| 				If the caller is already on the list, only update CallerData
 | |
| 			*/
 | |
| 			for(typename std::deque< GetRequest<Key, T, Caller, CallerData> >::iterator
 | |
| 					i = m_queue.getQueue().begin();
 | |
| 					i != m_queue.getQueue().end(); ++i)
 | |
| 			{
 | |
| 				GetRequest<Key, T, Caller, CallerData> &request = *i;
 | |
| 
 | |
| 				if(request.key == key)
 | |
| 				{
 | |
| 					for(typename std::list< CallerInfo<Caller, CallerData, Key, T> >::iterator
 | |
| 							i = request.callers.begin();
 | |
| 							i != request.callers.end(); ++i)
 | |
| 					{
 | |
| 						CallerInfo<Caller, CallerData, Key, T> &ca = *i;
 | |
| 						if(ca.caller == caller)
 | |
| 						{
 | |
| 							ca.data = callerdata;
 | |
| 							return;
 | |
| 						}
 | |
| 					}
 | |
| 					CallerInfo<Caller, CallerData, Key, T> ca;
 | |
| 					ca.caller = caller;
 | |
| 					ca.data = callerdata;
 | |
| 					ca.dest = dest;
 | |
| 					request.callers.push_back(ca);
 | |
| 					return;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		/*
 | |
| 			Else add a new request to the queue
 | |
| 		*/
 | |
| 
 | |
| 		GetRequest<Key, T, Caller, CallerData> request;
 | |
| 		request.key = key;
 | |
| 		CallerInfo<Caller, CallerData, Key, T> ca;
 | |
| 		ca.caller = caller;
 | |
| 		ca.data = callerdata;
 | |
| 		ca.dest = dest;
 | |
| 		request.callers.push_back(ca);
 | |
| 		
 | |
| 		m_queue.push_back(request);
 | |
| 	}
 | |
| 
 | |
| 	GetRequest<Key, T, Caller, CallerData> pop(unsigned int timeout_ms)
 | |
| 	{
 | |
| 		return m_queue.pop_front(timeout_ms);
 | |
| 	}
 | |
| 
 | |
| 	GetRequest<Key, T, Caller, CallerData> pop()
 | |
| 	{
 | |
| 		return m_queue.pop_frontNoEx();
 | |
| 	}
 | |
| 
 | |
| 	void pushResult(GetRequest<Key, T, Caller, CallerData> req,
 | |
| 					T res) {
 | |
| 
 | |
| 		for(typename std::list< CallerInfo<Caller, CallerData, Key, T> >::iterator
 | |
| 				i = req.callers.begin();
 | |
| 				i != req.callers.end(); ++i)
 | |
| 		{
 | |
| 			CallerInfo<Caller, CallerData, Key, T> &ca = *i;
 | |
| 
 | |
| 			GetResult<Key,T,Caller,CallerData> result;
 | |
| 
 | |
| 			result.key = req.key;
 | |
| 			result.item = res;
 | |
| 			result.caller.first = ca.caller;
 | |
| 			result.caller.second = ca.data;
 | |
| 
 | |
| 			ca.dest->push_back(result);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| private:
 | |
| 	MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
 | |
| };
 | |
| 
 | |
| #endif
 | |
| 
 |