Use multi-threads to process files

This commit is contained in:
quqiOnfree 2025-02-16 15:00:01 +08:00 committed by Xuan Xiao
parent 3fe1518325
commit c188a824ad
3 changed files with 106 additions and 25 deletions

View File

@ -52,6 +52,7 @@ if(WIN32)
target_link_options(ncmdump_lib PRIVATE -static)
endif()
else()
set(CMAKE_CXX_FLAGS -pthread)
add_executable(ncmdump_exec
${COMMON_HEADERS}
${COMMON_SOURCES}

View File

@ -0,0 +1,73 @@
#pragma once
#include <thread>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <atomic>
#include <functional>
#include <memory>
namespace cxxpool
{
class ThreadPool
{
public:
ThreadPool():
thread_num_(std::thread::hardware_concurrency() * 2),
is_running_(true)
{
work_threads_ = std::make_unique<std::thread[]>(thread_num_);
for (unsigned int i = 0; i < thread_num_; ++i)
{
work_threads_[i] = std::thread([&](){
while (true)
{
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait(lock, [&](){ return !is_running_ || !queue_.empty(); });
if (!is_running_ && queue_.empty())
return;
else if (queue_.empty())
continue;
std::function<void()> func = std::move(queue_.front());
queue_.pop();
lock.unlock();
std::invoke(func);
}
});
}
}
~ThreadPool() noexcept
{
is_running_ = false;
cv_.notify_all();
for (unsigned int i = 0; i < thread_num_; ++i)
{
if (work_threads_[i].joinable())
work_threads_[i].join();
}
}
template<class Func, class... Args>
void submit(Func&& func, Args&&... args)
{
std::unique_lock<std::mutex> lock(mutex_);
queue_.push(std::bind(func, std::forward<Args>(args)...));
lock.unlock();
cv_.notify_one();
}
private:
const unsigned int thread_num_;
std::unique_ptr<std::thread[]> work_threads_;
std::mutex mutex_;
std::atomic<bool> is_running_;
std::condition_variable cv_;
std::queue<std::function<void()>> queue_;
};
} // namespace cxxpool

View File

@ -12,39 +12,46 @@
#include "color.h"
#include "version.h"
#include "cxxopts.hpp"
#include "thread_pool.hpp"
namespace fs = std::filesystem;
cxxpool::ThreadPool thread_pool;
void processFile(const fs::path &filePath, const fs::path &outputFolder)
{
if (fs::exists(filePath) == false)
{
std::cerr << BOLDRED << "[Error] " << RESET << "file '" << filePath.u8string() << "' does not exist." << std::endl;
return;
}
auto work_func = [](fs::path filePath, fs::path outputFolder) {
if (fs::exists(filePath) == false)
{
std::cerr << BOLDRED << "[Error] " << RESET << "file '" << filePath.u8string() << "' does not exist." << std::endl;
return;
}
// skip if not ending with ".ncm"
if (!filePath.has_extension() || filePath.extension().u8string() != ".ncm")
{
return;
}
// skip if not ending with ".ncm"
if (!filePath.has_extension() || filePath.extension().u8string() != ".ncm")
{
return;
}
try
{
NeteaseCrypt crypt(filePath.u8string());
crypt.Dump(outputFolder.u8string());
crypt.FixMetadata();
try
{
NeteaseCrypt crypt(filePath.u8string());
crypt.Dump(outputFolder.u8string());
crypt.FixMetadata();
std::cout << BOLDGREEN << "[Done] " << RESET << "'" << filePath.u8string() << "' -> '" << crypt.dumpFilepath().u8string() << "'" << std::endl;
}
catch (const std::invalid_argument &e)
{
std::cerr << BOLDRED << "[Exception] " << RESET << RED << e.what() << RESET << " '" << filePath.u8string() << "'" << std::endl;
}
catch (...)
{
std::cerr << BOLDRED << "[Error] Unexpected exception while processing file: " << RESET << filePath.u8string() << std::endl;
}
std::cout << BOLDGREEN << "[Done] " << RESET << "'" << filePath.u8string() << "' -> '" << crypt.dumpFilepath().u8string() << "'" << std::endl;
}
catch (const std::invalid_argument &e)
{
std::cerr << BOLDRED << "[Exception] " << RESET << RED << e.what() << RESET << " '" << filePath.u8string() << "'" << std::endl;
}
catch (...)
{
std::cerr << BOLDRED << "[Error] Unexpected exception while processing file: " << RESET << filePath.u8string() << std::endl;
}
};
thread_pool.submit(work_func, filePath, outputFolder);
}
int main(int argc, char **argv)