mirror of
https://github.com/ModOrganizer2/mob.git
synced 2026-07-27 14:07:05 -07:00
split threading
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include "core/conf.h"
|
||||
#include "tasks/tasks.h"
|
||||
#include "tools/tools.h"
|
||||
#include "utility/threading.h"
|
||||
|
||||
namespace mob
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "core/op.h"
|
||||
#include "tasks/tasks.h"
|
||||
#include "tools/tools.h"
|
||||
#include "utility/threading.h"
|
||||
|
||||
namespace mob
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "core/conf.h"
|
||||
#include "core/op.h"
|
||||
#include "core/context.h"
|
||||
#include "utility/threading.h"
|
||||
|
||||
namespace mob
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "../core/conf.h"
|
||||
#include "../core/op.h"
|
||||
#include "../tools/tools.h"
|
||||
#include "../utility/threading.h"
|
||||
|
||||
namespace mob
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "pch.h"
|
||||
#include "tasks.h"
|
||||
#include "../utility/threading.h"
|
||||
|
||||
namespace mob
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "pch.h"
|
||||
#include "tools.h"
|
||||
#include "../core/conf.h"
|
||||
#include "../utility/threading.h"
|
||||
|
||||
namespace mob
|
||||
{
|
||||
|
||||
+6
-232
@@ -14,179 +14,6 @@ static std::mutex g_output_mutex;
|
||||
extern u8stream u8cout(false);
|
||||
extern u8stream u8cerr(true);
|
||||
|
||||
constexpr std::size_t max_name_length = 1000;
|
||||
constexpr std::size_t max_frames = 100;
|
||||
const std::size_t exception_message_length = 5000;
|
||||
|
||||
static void* frame_addresses[max_frames];
|
||||
static wchar_t undecorated_name[max_name_length + 1] = {};
|
||||
static unsigned char sym_buffer[sizeof(SYMBOL_INFOW) + max_name_length];
|
||||
static SYMBOL_INFOW* sym = (SYMBOL_INFOW*)sym_buffer;
|
||||
static wchar_t exception_message[exception_message_length + 1] = {};
|
||||
|
||||
static LPTOP_LEVEL_EXCEPTION_FILTER g_previous_handler = nullptr;
|
||||
|
||||
void dump_stacktrace(const wchar_t* what)
|
||||
{
|
||||
std::scoped_lock lock(g_output_mutex);
|
||||
|
||||
std::wcerr
|
||||
<< "\n\nmob has crashed\n"
|
||||
<< L"*****************************\n\n"
|
||||
<< what << L"\n\n";
|
||||
|
||||
|
||||
HANDLE process = INVALID_HANDLE_VALUE;
|
||||
|
||||
DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
|
||||
GetCurrentProcess(), &process, 0, false, DUPLICATE_SAME_ACCESS);
|
||||
|
||||
SymSetOptions(SymGetOptions() & (~SYMOPT_UNDNAME));
|
||||
SymInitializeW(process, NULL, TRUE);
|
||||
|
||||
const std::size_t frame_count = CaptureStackBackTrace(
|
||||
0, max_frames, frame_addresses, nullptr);
|
||||
|
||||
for (std::size_t i=0; i<frame_count; ++i)
|
||||
{
|
||||
DWORD disp = 0;
|
||||
IMAGEHLP_LINEW64 line = {0};
|
||||
line.SizeOfStruct = sizeof(line);
|
||||
|
||||
std::wcerr << frame_addresses[i] << L" ";
|
||||
|
||||
if (SymGetLineFromAddrW64(
|
||||
process, reinterpret_cast<DWORD64>(frame_addresses[i]),
|
||||
&disp, &line))
|
||||
{
|
||||
std::wcerr << line.FileName << L":" << line.LineNumber << L" ";
|
||||
}
|
||||
|
||||
DWORD64 disp2 = 0;
|
||||
|
||||
sym->MaxNameLen = max_name_length;
|
||||
sym->SizeOfStruct = sizeof(SYMBOL_INFOW);
|
||||
|
||||
if (SymFromAddrW(process, reinterpret_cast<DWORD64>(frame_addresses[i]), &disp2, sym))
|
||||
{
|
||||
const DWORD und_length = UnDecorateSymbolNameW(
|
||||
sym->Name, undecorated_name, max_name_length, UNDNAME_COMPLETE);
|
||||
|
||||
std::wcerr << undecorated_name;
|
||||
}
|
||||
|
||||
std::wcerr << L"\n";
|
||||
}
|
||||
|
||||
if (IsDebuggerPresent())
|
||||
DebugBreak();
|
||||
else
|
||||
TerminateProcess(GetCurrentProcess(), 0xffff);
|
||||
}
|
||||
|
||||
void terminate_handler() noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
std::rethrow_exception(std::current_exception());
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
auto* p = exception_message;
|
||||
std::size_t remaining = exception_message_length;
|
||||
|
||||
const int n = _snwprintf(
|
||||
p, remaining, L"%s", L"unhandled exception: ");
|
||||
|
||||
if (n >= 0)
|
||||
{
|
||||
p += n;
|
||||
remaining -=n ;
|
||||
}
|
||||
|
||||
::MultiByteToWideChar(
|
||||
CP_ACP, 0, e.what(), -1, p, static_cast<int>(remaining));
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
auto* p = exception_message;
|
||||
std::size_t remaining = exception_message_length;
|
||||
|
||||
_snwprintf(
|
||||
p, remaining, L"%s", L"unhandled exception");
|
||||
}
|
||||
|
||||
dump_stacktrace(exception_message);
|
||||
}
|
||||
|
||||
const wchar_t* error_code_name(DWORD code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case EXCEPTION_ACCESS_VIOLATION: return L"EXCEPTION_ACCESS_VIOLATION";
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return L"EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
|
||||
case EXCEPTION_BREAKPOINT: return L"EXCEPTION_BREAKPOINT";
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT: return L"EXCEPTION_DATATYPE_MISALIGNMENT";
|
||||
case EXCEPTION_FLT_DENORMAL_OPERAND: return L"EXCEPTION_FLT_DENORMAL_OPERAND";
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO: return L"EXCEPTION_FLT_DIVIDE_BY_ZERO";
|
||||
case EXCEPTION_FLT_INEXACT_RESULT: return L"EXCEPTION_FLT_INEXACT_RESULT";
|
||||
case EXCEPTION_FLT_INVALID_OPERATION: return L"EXCEPTION_FLT_INVALID_OPERATION";
|
||||
case EXCEPTION_FLT_OVERFLOW: return L"EXCEPTION_FLT_OVERFLOW";
|
||||
case EXCEPTION_FLT_STACK_CHECK: return L"EXCEPTION_FLT_STACK_CHECK";
|
||||
case EXCEPTION_FLT_UNDERFLOW: return L"EXCEPTION_FLT_UNDERFLOW";
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION: return L"EXCEPTION_ILLEGAL_INSTRUCTION";
|
||||
case EXCEPTION_IN_PAGE_ERROR: return L"EXCEPTION_IN_PAGE_ERROR";
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO: return L"EXCEPTION_INT_DIVIDE_BY_ZERO";
|
||||
case EXCEPTION_INT_OVERFLOW: return L"EXCEPTION_INT_OVERFLOW";
|
||||
case EXCEPTION_INVALID_DISPOSITION: return L"EXCEPTION_INVALID_DISPOSITION";
|
||||
case EXCEPTION_NONCONTINUABLE_EXCEPTION: return L"EXCEPTION_NONCONTINUABLE_EXCEPTION";
|
||||
case EXCEPTION_PRIV_INSTRUCTION: return L"EXCEPTION_PRIV_INSTRUCTION";
|
||||
case EXCEPTION_SINGLE_STEP: return L"EXCEPTION_SINGLE_STEP";
|
||||
case EXCEPTION_STACK_OVERFLOW: return L"EXCEPTION_STACK_OVERFLOW";
|
||||
default: return L"unknown exception" ;
|
||||
}
|
||||
}
|
||||
|
||||
LONG WINAPI unhandled_exception_handler(LPEXCEPTION_POINTERS ep) noexcept
|
||||
{
|
||||
if (ep->ExceptionRecord->ExceptionCode == 0xE06D7363)
|
||||
{
|
||||
if (g_previous_handler)
|
||||
return g_previous_handler(ep);;
|
||||
}
|
||||
|
||||
wchar_t* p = exception_message;
|
||||
std::size_t remaining = exception_message_length;
|
||||
|
||||
const auto n = GetModuleFileNameW(
|
||||
GetModuleHandleW(nullptr), exception_message,
|
||||
exception_message_length);
|
||||
|
||||
p += n;
|
||||
remaining -= n;
|
||||
|
||||
const auto n2 = _snwprintf(
|
||||
p, remaining, L": exception thrown at 0x%p: 0x%lX %s",
|
||||
ep->ExceptionRecord->ExceptionAddress,
|
||||
ep->ExceptionRecord->ExceptionCode,
|
||||
error_code_name(ep->ExceptionRecord->ExceptionCode));
|
||||
|
||||
p += n2;
|
||||
remaining -= n2;
|
||||
|
||||
|
||||
dump_stacktrace(exception_message);
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
void set_thread_exception_handlers()
|
||||
{
|
||||
g_previous_handler = SetUnhandledExceptionFilter(
|
||||
mob::unhandled_exception_handler);
|
||||
|
||||
std::set_terminate(mob::terminate_handler);
|
||||
}
|
||||
|
||||
|
||||
static bool stdout_console = []
|
||||
{
|
||||
@@ -224,6 +51,12 @@ void set_std_streams()
|
||||
_setmode(_fileno(stderr), _O_U16TEXT);
|
||||
}
|
||||
|
||||
std::mutex& global_output_mutex()
|
||||
{
|
||||
return g_output_mutex;
|
||||
}
|
||||
|
||||
|
||||
void u8stream::do_output(const std::string& s)
|
||||
{
|
||||
std::scoped_lock lock(g_output_mutex);
|
||||
@@ -967,63 +800,4 @@ std::string path_to_utf8(fs::path p)
|
||||
return utf16_to_utf8(p.native());
|
||||
}
|
||||
|
||||
|
||||
|
||||
thread_pool::thread_pool(std::size_t count)
|
||||
: count_(std::max<std::size_t>(1, count))
|
||||
{
|
||||
for (std::size_t i=0; i<count_; ++i)
|
||||
threads_.emplace_back(std::make_unique<thread_info>());
|
||||
}
|
||||
|
||||
thread_pool::~thread_pool()
|
||||
{
|
||||
join();
|
||||
}
|
||||
|
||||
void thread_pool::join()
|
||||
{
|
||||
for (auto&& t : threads_)
|
||||
{
|
||||
if (t->thread.joinable())
|
||||
t->thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void thread_pool::add(fun thread_fun)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (try_add(thread_fun))
|
||||
break;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
bool thread_pool::try_add(fun thread_fun)
|
||||
{
|
||||
for (auto& t : threads_)
|
||||
{
|
||||
if (!t->running)
|
||||
{
|
||||
if (t->thread.joinable())
|
||||
t->thread.join();
|
||||
|
||||
t->running = true;
|
||||
t->thread_fun = thread_fun;
|
||||
|
||||
t->thread = std::thread([&]
|
||||
{
|
||||
t->thread_fun();
|
||||
t->running = false;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
+1
-43
@@ -51,18 +51,6 @@ inline void mob_assert(
|
||||
mob_assertion_failed(nullptr, exp, file, line, func);
|
||||
}
|
||||
|
||||
void set_thread_exception_handlers();
|
||||
|
||||
template <class F>
|
||||
std::thread start_thread(F&& f)
|
||||
{
|
||||
return std::thread([f]
|
||||
{
|
||||
set_thread_exception_handlers();
|
||||
f();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
enum class encodings
|
||||
{
|
||||
@@ -395,6 +383,7 @@ extern u8stream u8cout;
|
||||
extern u8stream u8cerr;
|
||||
|
||||
void set_std_streams();
|
||||
std::mutex& global_output_mutex();
|
||||
|
||||
|
||||
template <class F>
|
||||
@@ -590,37 +579,6 @@ auto map(const std::vector<T>& v, F&& f)
|
||||
}
|
||||
|
||||
|
||||
class thread_pool
|
||||
{
|
||||
public:
|
||||
typedef std::function<void ()> fun;
|
||||
|
||||
thread_pool(std::size_t count=std::thread::hardware_concurrency());
|
||||
~thread_pool();
|
||||
|
||||
// non-copyable
|
||||
thread_pool(const thread_pool&) = delete;
|
||||
thread_pool& operator=(const thread_pool&) = delete;
|
||||
|
||||
void add(fun f);
|
||||
void join();
|
||||
|
||||
private:
|
||||
struct thread_info
|
||||
{
|
||||
std::atomic<bool> running = false;
|
||||
fun thread_fun;
|
||||
std::thread thread;
|
||||
};
|
||||
|
||||
|
||||
const std::size_t count_;
|
||||
std::vector<std::unique_ptr<thread_info>> threads_;
|
||||
|
||||
bool try_add(fun thread_fun);
|
||||
};
|
||||
|
||||
|
||||
// see https://github.com/isanae/mob/issues/4
|
||||
//
|
||||
// this restores the original console font if it changed
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
// for intellisense
|
||||
#include "../pch.h"
|
||||
@@ -0,0 +1,239 @@
|
||||
#include "pch.h"
|
||||
#include "threading.h"
|
||||
#include "../utility.h"
|
||||
|
||||
namespace mob
|
||||
{
|
||||
|
||||
constexpr std::size_t max_name_length = 1000;
|
||||
constexpr std::size_t max_frames = 100;
|
||||
const std::size_t exception_message_length = 5000;
|
||||
|
||||
static void* frame_addresses[max_frames];
|
||||
static wchar_t undecorated_name[max_name_length + 1] = {};
|
||||
static unsigned char sym_buffer[sizeof(SYMBOL_INFOW) + max_name_length];
|
||||
static SYMBOL_INFOW* sym = (SYMBOL_INFOW*)sym_buffer;
|
||||
static wchar_t exception_message[exception_message_length + 1] = {};
|
||||
|
||||
static LPTOP_LEVEL_EXCEPTION_FILTER g_previous_handler = nullptr;
|
||||
|
||||
void dump_stacktrace(const wchar_t* what)
|
||||
{
|
||||
std::scoped_lock lock(global_output_mutex());
|
||||
|
||||
std::wcerr
|
||||
<< "\n\nmob has crashed\n"
|
||||
<< L"*****************************\n\n"
|
||||
<< what << L"\n\n";
|
||||
|
||||
|
||||
HANDLE process = INVALID_HANDLE_VALUE;
|
||||
|
||||
DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
|
||||
GetCurrentProcess(), &process, 0, false, DUPLICATE_SAME_ACCESS);
|
||||
|
||||
SymSetOptions(SymGetOptions() & (~SYMOPT_UNDNAME));
|
||||
SymInitializeW(process, NULL, TRUE);
|
||||
|
||||
const std::size_t frame_count = CaptureStackBackTrace(
|
||||
0, max_frames, frame_addresses, nullptr);
|
||||
|
||||
for (std::size_t i=0; i<frame_count; ++i)
|
||||
{
|
||||
DWORD disp = 0;
|
||||
IMAGEHLP_LINEW64 line = {0};
|
||||
line.SizeOfStruct = sizeof(line);
|
||||
|
||||
std::wcerr << frame_addresses[i] << L" ";
|
||||
|
||||
if (SymGetLineFromAddrW64(
|
||||
process, reinterpret_cast<DWORD64>(frame_addresses[i]),
|
||||
&disp, &line))
|
||||
{
|
||||
std::wcerr << line.FileName << L":" << line.LineNumber << L" ";
|
||||
}
|
||||
|
||||
DWORD64 disp2 = 0;
|
||||
|
||||
sym->MaxNameLen = max_name_length;
|
||||
sym->SizeOfStruct = sizeof(SYMBOL_INFOW);
|
||||
|
||||
if (SymFromAddrW(process, reinterpret_cast<DWORD64>(frame_addresses[i]), &disp2, sym))
|
||||
{
|
||||
const DWORD und_length = UnDecorateSymbolNameW(
|
||||
sym->Name, undecorated_name, max_name_length, UNDNAME_COMPLETE);
|
||||
|
||||
std::wcerr << undecorated_name;
|
||||
}
|
||||
|
||||
std::wcerr << L"\n";
|
||||
}
|
||||
|
||||
if (IsDebuggerPresent())
|
||||
DebugBreak();
|
||||
else
|
||||
TerminateProcess(GetCurrentProcess(), 0xffff);
|
||||
}
|
||||
|
||||
void terminate_handler() noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
std::rethrow_exception(std::current_exception());
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
auto* p = exception_message;
|
||||
std::size_t remaining = exception_message_length;
|
||||
|
||||
const int n = _snwprintf(
|
||||
p, remaining, L"%s", L"unhandled exception: ");
|
||||
|
||||
if (n >= 0)
|
||||
{
|
||||
p += n;
|
||||
remaining -=n ;
|
||||
}
|
||||
|
||||
::MultiByteToWideChar(
|
||||
CP_ACP, 0, e.what(), -1, p, static_cast<int>(remaining));
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
auto* p = exception_message;
|
||||
std::size_t remaining = exception_message_length;
|
||||
|
||||
_snwprintf(
|
||||
p, remaining, L"%s", L"unhandled exception");
|
||||
}
|
||||
|
||||
dump_stacktrace(exception_message);
|
||||
}
|
||||
|
||||
const wchar_t* error_code_name(DWORD code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case EXCEPTION_ACCESS_VIOLATION: return L"EXCEPTION_ACCESS_VIOLATION";
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return L"EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
|
||||
case EXCEPTION_BREAKPOINT: return L"EXCEPTION_BREAKPOINT";
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT: return L"EXCEPTION_DATATYPE_MISALIGNMENT";
|
||||
case EXCEPTION_FLT_DENORMAL_OPERAND: return L"EXCEPTION_FLT_DENORMAL_OPERAND";
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO: return L"EXCEPTION_FLT_DIVIDE_BY_ZERO";
|
||||
case EXCEPTION_FLT_INEXACT_RESULT: return L"EXCEPTION_FLT_INEXACT_RESULT";
|
||||
case EXCEPTION_FLT_INVALID_OPERATION: return L"EXCEPTION_FLT_INVALID_OPERATION";
|
||||
case EXCEPTION_FLT_OVERFLOW: return L"EXCEPTION_FLT_OVERFLOW";
|
||||
case EXCEPTION_FLT_STACK_CHECK: return L"EXCEPTION_FLT_STACK_CHECK";
|
||||
case EXCEPTION_FLT_UNDERFLOW: return L"EXCEPTION_FLT_UNDERFLOW";
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION: return L"EXCEPTION_ILLEGAL_INSTRUCTION";
|
||||
case EXCEPTION_IN_PAGE_ERROR: return L"EXCEPTION_IN_PAGE_ERROR";
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO: return L"EXCEPTION_INT_DIVIDE_BY_ZERO";
|
||||
case EXCEPTION_INT_OVERFLOW: return L"EXCEPTION_INT_OVERFLOW";
|
||||
case EXCEPTION_INVALID_DISPOSITION: return L"EXCEPTION_INVALID_DISPOSITION";
|
||||
case EXCEPTION_NONCONTINUABLE_EXCEPTION: return L"EXCEPTION_NONCONTINUABLE_EXCEPTION";
|
||||
case EXCEPTION_PRIV_INSTRUCTION: return L"EXCEPTION_PRIV_INSTRUCTION";
|
||||
case EXCEPTION_SINGLE_STEP: return L"EXCEPTION_SINGLE_STEP";
|
||||
case EXCEPTION_STACK_OVERFLOW: return L"EXCEPTION_STACK_OVERFLOW";
|
||||
default: return L"unknown exception" ;
|
||||
}
|
||||
}
|
||||
|
||||
LONG WINAPI unhandled_exception_handler(LPEXCEPTION_POINTERS ep) noexcept
|
||||
{
|
||||
if (ep->ExceptionRecord->ExceptionCode == 0xE06D7363)
|
||||
{
|
||||
if (g_previous_handler)
|
||||
return g_previous_handler(ep);;
|
||||
}
|
||||
|
||||
wchar_t* p = exception_message;
|
||||
std::size_t remaining = exception_message_length;
|
||||
|
||||
const auto n = GetModuleFileNameW(
|
||||
GetModuleHandleW(nullptr), exception_message,
|
||||
exception_message_length);
|
||||
|
||||
p += n;
|
||||
remaining -= n;
|
||||
|
||||
const auto n2 = _snwprintf(
|
||||
p, remaining, L": exception thrown at 0x%p: 0x%lX %s",
|
||||
ep->ExceptionRecord->ExceptionAddress,
|
||||
ep->ExceptionRecord->ExceptionCode,
|
||||
error_code_name(ep->ExceptionRecord->ExceptionCode));
|
||||
|
||||
p += n2;
|
||||
remaining -= n2;
|
||||
|
||||
|
||||
dump_stacktrace(exception_message);
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
void set_thread_exception_handlers()
|
||||
{
|
||||
g_previous_handler = SetUnhandledExceptionFilter(
|
||||
mob::unhandled_exception_handler);
|
||||
|
||||
std::set_terminate(mob::terminate_handler);
|
||||
}
|
||||
|
||||
|
||||
thread_pool::thread_pool(std::size_t count)
|
||||
: count_(std::max<std::size_t>(1, count))
|
||||
{
|
||||
for (std::size_t i=0; i<count_; ++i)
|
||||
threads_.emplace_back(std::make_unique<thread_info>());
|
||||
}
|
||||
|
||||
thread_pool::~thread_pool()
|
||||
{
|
||||
join();
|
||||
}
|
||||
|
||||
void thread_pool::join()
|
||||
{
|
||||
for (auto&& t : threads_)
|
||||
{
|
||||
if (t->thread.joinable())
|
||||
t->thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void thread_pool::add(fun thread_fun)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (try_add(thread_fun))
|
||||
break;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
bool thread_pool::try_add(fun thread_fun)
|
||||
{
|
||||
for (auto& t : threads_)
|
||||
{
|
||||
if (!t->running)
|
||||
{
|
||||
if (t->thread.joinable())
|
||||
t->thread.join();
|
||||
|
||||
t->running = true;
|
||||
t->thread_fun = thread_fun;
|
||||
|
||||
t->thread = std::thread([&]
|
||||
{
|
||||
t->thread_fun();
|
||||
t->running = false;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
namespace mob
|
||||
{
|
||||
|
||||
void set_thread_exception_handlers();
|
||||
|
||||
template <class F>
|
||||
std::thread start_thread(F&& f)
|
||||
{
|
||||
return std::thread([f]
|
||||
{
|
||||
set_thread_exception_handlers();
|
||||
f();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
class thread_pool
|
||||
{
|
||||
public:
|
||||
typedef std::function<void ()> fun;
|
||||
|
||||
thread_pool(std::size_t count=std::thread::hardware_concurrency());
|
||||
~thread_pool();
|
||||
|
||||
// non-copyable
|
||||
thread_pool(const thread_pool&) = delete;
|
||||
thread_pool& operator=(const thread_pool&) = delete;
|
||||
|
||||
void add(fun f);
|
||||
void join();
|
||||
|
||||
private:
|
||||
struct thread_info
|
||||
{
|
||||
std::atomic<bool> running = false;
|
||||
fun thread_fun;
|
||||
std::thread thread;
|
||||
};
|
||||
|
||||
|
||||
const std::size_t count_;
|
||||
std::vector<std::unique_ptr<thread_info>> threads_;
|
||||
|
||||
bool try_add(fun thread_fun);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -106,6 +106,7 @@
|
||||
<ClCompile Include="..\src\tools\process_runner.cpp" />
|
||||
<ClCompile Include="..\src\tools\tools.cpp" />
|
||||
<ClCompile Include="..\src\utility.cpp" />
|
||||
<ClCompile Include="..\src\utility\threading.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\commands.h" />
|
||||
@@ -120,6 +121,7 @@
|
||||
<ClInclude Include="..\src\tasks\tasks.h" />
|
||||
<ClInclude Include="..\src\tools\tools.h" />
|
||||
<ClInclude Include="..\src\utility.h" />
|
||||
<ClInclude Include="..\src\utility\threading.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
<Filter Include="src\core">
|
||||
<UniqueIdentifier>{6e4d31d5-100c-4a4d-8e7d-4c48939819bd}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src\utility">
|
||||
<UniqueIdentifier>{78dd6066-d407-4450-b520-649454c15ee9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\main.cpp">
|
||||
@@ -150,6 +153,9 @@
|
||||
<ClCompile Include="..\src\core\context.cpp">
|
||||
<Filter>src\core</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\utility\threading.cpp">
|
||||
<Filter>src\utility</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\pch.h">
|
||||
@@ -188,5 +194,8 @@
|
||||
<ClInclude Include="..\src\core\conf.h">
|
||||
<Filter>src\core</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\src\utility\threading.h">
|
||||
<Filter>src\utility</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user