Merge pull request #5951 from ligfx/gametrackerworkqueuethread

GameTracker: use new Common::WorkQueueThread instead of signals/slots
This commit is contained in:
Anthony 2017-08-23 08:02:36 -07:00 committed by GitHub
commit 935c1da357
5 changed files with 96 additions and 39 deletions

View File

@ -151,6 +151,7 @@
<ClInclude Include="TraversalClient.h" />
<ClInclude Include="TraversalProto.h" />
<ClInclude Include="UPnP.h" />
<ClInclude Include="WorkQueueThread.h" />
<ClInclude Include="x64ABI.h" />
<ClInclude Include="x64Emitter.h" />
<ClInclude Include="x64Reg.h" />

View File

@ -68,6 +68,7 @@
<ClInclude Include="SysConf.h" />
<ClInclude Include="Thread.h" />
<ClInclude Include="Timer.h" />
<ClInclude Include="WorkQueueThread.h" />
<ClInclude Include="x64ABI.h" />
<ClInclude Include="x64Emitter.h" />
<ClInclude Include="x64Reg.h" />

View File

@ -0,0 +1,86 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <functional>
#include <queue>
#include <thread>
#include "Common/Event.h"
#include "Common/Flag.h"
// A thread that executes the given function for every item placed into its queue.
namespace Common
{
template <typename T>
class WorkQueueThread
{
public:
WorkQueueThread() = default;
WorkQueueThread(std::function<void(T)> function) { Reset(std::move(function)); }
~WorkQueueThread() { Shutdown(); }
void Reset(std::function<void(T)> function)
{
Shutdown();
m_shutdown.Clear();
m_function = std::move(function);
m_thread = std::thread([this] { ThreadLoop(); });
}
template <typename... Args>
void EmplaceItem(Args&&... args)
{
{
std::unique_lock<std::mutex> lg(m_lock);
m_items.emplace(std::forward<Args>(args)...);
}
m_wakeup.Set();
}
private:
void Shutdown()
{
if (m_thread.joinable())
{
m_shutdown.Set();
m_wakeup.Set();
m_thread.join();
}
}
void ThreadLoop()
{
while (true)
{
m_wakeup.Wait();
while (true)
{
T item;
{
std::unique_lock<std::mutex> lg(m_lock);
if (m_items.empty())
break;
item = m_items.front();
m_items.pop();
}
m_function(std::move(item));
}
if (m_shutdown.IsSet())
break;
}
}
std::function<void(T)> m_function;
std::thread m_thread;
Common::Event m_wakeup;
Common::Flag m_shutdown;
std::mutex m_lock;
std::queue<T> m_items;
};
} // namespace Common

View File

@ -17,23 +17,11 @@ static const QStringList game_filters{
GameTracker::GameTracker(QObject* parent) : QFileSystemWatcher(parent)
{
m_loader = new GameLoader;
m_loader->moveToThread(&m_loader_thread);
qRegisterMetaType<QSharedPointer<GameFile>>();
connect(&m_loader_thread, &QThread::finished, m_loader, &QObject::deleteLater);
connect(this, &QFileSystemWatcher::directoryChanged, this, &GameTracker::UpdateDirectory);
connect(this, &QFileSystemWatcher::fileChanged, this, &GameTracker::UpdateFile);
connect(this, &GameTracker::PathChanged, m_loader, &GameLoader::LoadGame);
connect(m_loader, &GameLoader::GameLoaded, this, &GameTracker::GameLoaded);
m_loader_thread.start();
}
GameTracker::~GameTracker()
{
m_loader_thread.quit();
m_loader_thread.wait();
m_load_thread.Reset([this](const QString& path) { LoadGame(path); });
}
void GameTracker::AddDirectory(const QString& dir)
@ -81,7 +69,7 @@ void GameTracker::UpdateDirectory(const QString& dir)
{
addPath(path);
m_tracked_files[path] = QSet<QString>{dir};
emit PathChanged(path);
m_load_thread.EmplaceItem(path);
}
}
@ -127,7 +115,7 @@ void GameTracker::UpdateFile(const QString& file)
GameRemoved(file);
addPath(file);
emit PathChanged(file);
m_load_thread.EmplaceItem(file);
}
else if (removePath(file))
{
@ -136,7 +124,7 @@ void GameTracker::UpdateFile(const QString& file)
}
}
void GameLoader::LoadGame(const QString& path)
void GameTracker::LoadGame(const QString& path)
{
if (!DiscIO::ShouldHideFromGameList(path.toStdString()))
{

View File

@ -9,25 +9,19 @@
#include <QSet>
#include <QSharedPointer>
#include <QString>
#include <QStringList>
#include <QThread>
#include "Common/WorkQueueThread.h"
#include "DolphinQt2/GameList/GameFile.h"
class GameLoader;
// Watches directories and loads GameFiles in a separate thread.
// To use this, just add directories using AddDirectory, and listen for the
// GameLoaded and GameRemoved signals. Ignore the PathChanged signal, it's
// only there because the Qt people made fileChanged and directoryChanged
// private.
// GameLoaded and GameRemoved signals.
class GameTracker final : public QFileSystemWatcher
{
Q_OBJECT
public:
explicit GameTracker(QObject* parent = nullptr);
~GameTracker();
void AddDirectory(const QString& dir);
void RemoveDirectory(const QString& dir);
@ -36,28 +30,15 @@ signals:
void GameLoaded(QSharedPointer<GameFile> game);
void GameRemoved(const QString& path);
void PathChanged(const QString& path);
private:
void LoadGame(const QString& path);
void UpdateDirectory(const QString& dir);
void UpdateFile(const QString& path);
QSet<QString> FindMissingFiles(const QString& dir);
// game path -> directories that track it
QMap<QString, QSet<QString>> m_tracked_files;
QThread m_loader_thread;
GameLoader* m_loader;
};
class GameLoader final : public QObject
{
Q_OBJECT
public:
void LoadGame(const QString& path);
signals:
void GameLoaded(QSharedPointer<GameFile> game);
Common::WorkQueueThread<QString> m_load_thread;
};
Q_DECLARE_METATYPE(QSharedPointer<GameFile>)