Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Пишем легкой ThreadPool с async и future

Anna | 25.06.2014 | нет комментариев
Доброе время суток! Я занимаюсь разработкой MMORPG. В игре асинхронной загрузкой файлов занимается файловая система встроенная в движок, остальная логика обрабатывалась в основном потоке. Но помимо загрузки файлов есть и другие массивные операции, скажем инициализация персонажа, которая включает в себя распарсивание XML данных, композиция текстур и т.д. И я столкнулся с необходимостью разгрузить стержневой поток игры для возрастания fps.
Вооружившись гуглом и прочитав несколько последних статей на Прогре о потоках, решил испробовать свои силы и написать свой велосипед ThreadPool. Стержневой моей целью было написать примитивный в применении и расширяемый пул потоков, с вероятностью асинхронного вызова функций с любым числом доводов и приобретения возвращаемого значения. Предлагаемые на Прогре решения меня не устроили в силу многих задач, от которых я постарался избавиться в своем решении – применять минимум шаблонной магии и отказаться от абстрактных классов и наследования. Я хочу поделиться своим навыком с вами.

И так, нужно реализовать каждого два класса, сам пул и класс рабочего потока, экземпляры которого будут управляться пулом.
Для реализации я применял следующие заголовочные файлы и классы:

#include <functional>
#include <thread>
#include <queue>
#include <mutex>
#include <memory>

using std::function;
using std::queue;
using std::mutex;
using std::thread;
using std::shared_ptr;
using std::vector;

Класс рабочего потока:

typedef function<void()> fn_type;

class Worker
{    
public:

	Worker()
		:enabled(true),fqueue()
		,thread(&Worker::thread_fn, this)
	{}
	~Worker()
	{
		enabled = false;
		thread.join();
	}  
	void appendFn(fn_type fn)
	{
		mutex.lock();
		fqueue.push(fn);
		mutex.unlock();
	}

	queue<fn_type>	fqueue;

protected:

	mutex		mutex;
	thread		thread;
	volatile bool	enabled;	

	void thread_fn();
};

typedef shared_ptr<Worker> worker_ptr;

Класс достаточно легкой, содержит мютекс для синхронизации, сам std::thread, флаг включения и очередь функторов std::function<void()>. Вы вероятно спросите – а как мы будем вызывать функции других типов? Результат ожидает вас ниже в статье.
Функция вызываемая в потоке будет выглядеть вот так:

void Worker::thread_fn()
{
	while (enabled)
	{
		if(!fqueue.empty())
		{
			mutex.lock();
			fn_type fn = fqueue.front();
			fqueue.pop();
			mutex.unlock();
			fn();
		}
		else
			std::this_thread::yield(); // В финальной реализации я применял здесь sleep
	}
}

В цикле просматриваем очередь на присутствие функторов. если обнаружили — вытягиваем и вызываем.
Это все, что нам нужно для этого класса.

Класс ThreadPool

Сейчас сам пул потоков. Я намеренно не стал прикручивать к нему плюшки типа очередей с приоритетами, синглтона и т.п. В статье мы разглядим только базовую реализацию. Все остальное при желании дозволено легко добавить.

class ThreadPool
{
public:

	ThreadPool(size_t threads = 1)
	{
		if (threads==0)
			threads=1;
		for (size_t i=0; i<threads; i  )
		{
			worker_ptr pWorker(new Worker);
			_workers.push_back(pWorker);
		}
	}
	~ThreadPool()
	{
		_workers.clear();
	}

protected:

	worker_ptr getFreeWorker();

	vector<worker_ptr> _workers; 

};

При создании в конструкторе дозволено указать сколько потоков будет применять пул.
Для приобретения потока в тот, что мы будем передавать наши функторы используем функцию getFreeWorker:

worker_ptr Worker::getFreeWorker()
{
	worker_ptr pWorker = _workers[0];
	size_t minTasks = pWorker->fqueue.size();				
	for (auto &it : _workers)
	{
		if (it->fqueue.empty())
			return it;
		else if (minTasks > it->fqueue.size())
		{
			minTasks = it->fqueue.size();
			pWorker = it;
		}
	}
	return pWorker;
}

Функция находит ближайший вольный поток либо наименее загруженный из них и возвращает его.
Таким об

 

Источник: programmingmaster.ru

 

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB