2012-11-14 23:39:56 +00:00
|
|
|
#pragma once
|
|
|
|
|
2016-02-01 21:55:43 +00:00
|
|
|
#include <string>
|
|
|
|
#include <memory>
|
|
|
|
#include <thread>
|
|
|
|
|
|
|
|
#include "Platform.h"
|
2016-04-25 10:49:12 +00:00
|
|
|
#include "Atomic.h"
|
2016-02-01 21:55:43 +00:00
|
|
|
|
2015-12-18 11:11:18 +00:00
|
|
|
// Will report exception and call std::abort() if put in catch(...)
|
|
|
|
[[noreturn]] void catch_all_exceptions();
|
|
|
|
|
2016-02-01 21:55:43 +00:00
|
|
|
// Simple list of void() functors
|
|
|
|
class task_stack
|
|
|
|
{
|
|
|
|
struct task_base
|
|
|
|
{
|
|
|
|
std::unique_ptr<task_base> next;
|
|
|
|
|
|
|
|
virtual ~task_base() = default;
|
|
|
|
|
|
|
|
virtual void exec()
|
|
|
|
{
|
|
|
|
if (next)
|
|
|
|
{
|
|
|
|
next->exec();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
std::unique_ptr<task_base> m_stack;
|
|
|
|
|
|
|
|
public:
|
|
|
|
template<typename F>
|
|
|
|
void push(F&& func)
|
|
|
|
{
|
|
|
|
struct task_t : task_base
|
|
|
|
{
|
|
|
|
std::remove_reference_t<F> func;
|
|
|
|
|
|
|
|
task_t(F&& func)
|
|
|
|
: func(std::forward<F>(func))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void exec() override
|
|
|
|
{
|
|
|
|
func();
|
|
|
|
task_base::exec();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-04-25 10:49:12 +00:00
|
|
|
auto _top = new task_t(std::forward<F>(func));
|
|
|
|
auto _next = m_stack.release();
|
|
|
|
m_stack.reset(_top);
|
|
|
|
#ifndef _MSC_VER
|
|
|
|
_top->next.reset(_next);
|
|
|
|
#else
|
|
|
|
auto& next = _top->next;
|
|
|
|
next.release();
|
|
|
|
next.reset(_next);
|
|
|
|
#endif
|
2016-02-01 21:55:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void reset()
|
|
|
|
{
|
|
|
|
m_stack.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void exec() const
|
|
|
|
{
|
|
|
|
if (m_stack)
|
|
|
|
{
|
|
|
|
m_stack->exec();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-11-26 08:06:29 +00:00
|
|
|
// Thread control class
|
|
|
|
class thread_ctrl final
|
2015-06-30 22:25:52 +00:00
|
|
|
{
|
2016-04-25 10:49:12 +00:00
|
|
|
struct internal;
|
2014-06-20 11:00:36 +00:00
|
|
|
|
2016-04-25 10:49:12 +00:00
|
|
|
static thread_local thread_ctrl* g_tls_this_thread;
|
2015-08-21 11:07:31 +00:00
|
|
|
|
2016-04-25 10:49:12 +00:00
|
|
|
// Thread handle
|
2015-06-30 22:25:52 +00:00
|
|
|
std::thread m_thread;
|
2015-02-18 16:22:06 +00:00
|
|
|
|
2016-04-25 10:49:12 +00:00
|
|
|
// Thread join contention counter
|
|
|
|
atomic_t<uint> m_joining{};
|
|
|
|
|
|
|
|
// Fixed name
|
|
|
|
std::string m_name;
|
2015-11-26 08:06:29 +00:00
|
|
|
|
2016-04-25 10:49:12 +00:00
|
|
|
// Thread internals
|
|
|
|
mutable atomic_t<internal*> m_data{};
|
2015-11-26 08:06:29 +00:00
|
|
|
|
|
|
|
// Called at the thread start
|
2016-04-25 10:49:12 +00:00
|
|
|
void initialize();
|
|
|
|
|
|
|
|
// Set std::current_exception
|
|
|
|
void set_exception() noexcept;
|
2015-08-21 11:07:31 +00:00
|
|
|
|
2015-11-26 08:06:29 +00:00
|
|
|
// Called at the thread end
|
2016-04-25 10:49:12 +00:00
|
|
|
void finalize() noexcept;
|
|
|
|
|
|
|
|
// Get atexit function
|
|
|
|
task_stack& get_atexit() const;
|
2012-11-14 23:39:56 +00:00
|
|
|
|
2014-01-31 18:40:18 +00:00
|
|
|
public:
|
2016-02-01 21:55:43 +00:00
|
|
|
template<typename N>
|
|
|
|
thread_ctrl(N&& name)
|
|
|
|
: m_name(std::forward<N>(name))
|
2015-06-30 22:25:52 +00:00
|
|
|
{
|
|
|
|
}
|
2012-11-14 23:39:56 +00:00
|
|
|
|
2015-11-26 08:06:29 +00:00
|
|
|
// Disable copy/move constructors and operators
|
|
|
|
thread_ctrl(const thread_ctrl&) = delete;
|
|
|
|
|
2016-04-25 10:49:12 +00:00
|
|
|
~thread_ctrl();
|
2015-09-26 20:46:04 +00:00
|
|
|
|
|
|
|
// Get thread name
|
2016-02-01 21:55:43 +00:00
|
|
|
const std::string& get_name() const
|
|
|
|
{
|
|
|
|
return m_name;
|
|
|
|
}
|
2012-11-14 23:39:56 +00:00
|
|
|
|
2016-04-25 10:49:12 +00:00
|
|
|
// Initialize internal data
|
|
|
|
void initialize_once() const;
|
2016-02-01 21:55:43 +00:00
|
|
|
|
2016-04-25 10:49:12 +00:00
|
|
|
// Get thread result (may throw, simultaneous joining allowed)
|
|
|
|
void join();
|
|
|
|
|
|
|
|
// Lock, unlock, notify the thread (required if the condition changed locklessly)
|
|
|
|
void lock_notify() const;
|
|
|
|
|
|
|
|
// Notify the thread, beware the condition change
|
|
|
|
void notify() const;
|
|
|
|
|
|
|
|
//
|
|
|
|
internal* get_data() const;
|
2015-11-26 08:06:29 +00:00
|
|
|
|
|
|
|
// Get current thread (may be nullptr)
|
|
|
|
static const thread_ctrl* get_current()
|
|
|
|
{
|
|
|
|
return g_tls_this_thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Register function at thread exit (for the current thread)
|
2016-02-01 21:55:43 +00:00
|
|
|
template<typename F>
|
|
|
|
static inline void at_exit(F&& func)
|
2015-11-26 08:06:29 +00:00
|
|
|
{
|
2016-04-25 10:49:12 +00:00
|
|
|
return g_tls_this_thread->get_atexit().push(std::forward<F>(func));
|
2015-11-26 08:06:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Named thread factory
|
2016-04-25 10:49:12 +00:00
|
|
|
template<typename N, typename F, typename... Args>
|
|
|
|
static inline std::shared_ptr<thread_ctrl> spawn(N&& name, F&& func, Args&&... args)
|
2015-11-26 08:06:29 +00:00
|
|
|
{
|
|
|
|
auto ctrl = std::make_shared<thread_ctrl>(std::forward<N>(name));
|
|
|
|
|
2016-04-25 10:49:12 +00:00
|
|
|
ctrl->m_thread = std::thread([ctrl, task = std::forward<F>(func)](Args&&... args)
|
2015-11-26 08:06:29 +00:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2016-04-25 10:49:12 +00:00
|
|
|
ctrl->initialize();
|
|
|
|
task(std::forward<Args>(args)...);
|
2015-11-26 08:06:29 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2016-04-25 10:49:12 +00:00
|
|
|
ctrl->set_exception();
|
2016-02-01 21:55:43 +00:00
|
|
|
}
|
2016-04-25 10:49:12 +00:00
|
|
|
|
|
|
|
ctrl->finalize();
|
|
|
|
|
|
|
|
}, std::forward<Args>(args)...);
|
2015-11-26 08:06:29 +00:00
|
|
|
|
|
|
|
return ctrl;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-02-01 21:55:43 +00:00
|
|
|
class named_thread : public std::enable_shared_from_this<named_thread>
|
2014-01-31 18:40:18 +00:00
|
|
|
{
|
2015-09-26 20:46:04 +00:00
|
|
|
// Pointer to managed resource (shared with actual thread)
|
2015-11-26 08:06:29 +00:00
|
|
|
std::shared_ptr<thread_ctrl> m_thread;
|
2015-01-16 14:36:53 +00:00
|
|
|
|
2015-06-30 22:25:52 +00:00
|
|
|
public:
|
2016-04-25 10:49:12 +00:00
|
|
|
named_thread();
|
2015-11-26 08:06:29 +00:00
|
|
|
|
2016-04-25 10:49:12 +00:00
|
|
|
virtual ~named_thread();
|
2015-06-30 22:25:52 +00:00
|
|
|
|
2016-04-25 10:49:12 +00:00
|
|
|
// Deleted copy/move constructors + copy/move operators
|
|
|
|
named_thread(const named_thread&) = delete;
|
2016-02-01 21:55:43 +00:00
|
|
|
|
2016-04-25 10:49:12 +00:00
|
|
|
// Get thread name
|
|
|
|
virtual std::string get_name() const;
|
2016-02-01 21:55:43 +00:00
|
|
|
|
2016-04-25 10:49:12 +00:00
|
|
|
protected:
|
|
|
|
// Start thread (cannot be called from the constructor: should throw bad_weak_ptr in such case)
|
|
|
|
void start();
|
|
|
|
|
|
|
|
// Thread task (called in the thread)
|
|
|
|
virtual void on_task() = 0;
|
|
|
|
|
|
|
|
// Thread finalization (called after on_task)
|
|
|
|
virtual void on_exit() {}
|
|
|
|
|
|
|
|
public:
|
2016-02-01 21:55:43 +00:00
|
|
|
// ID initialization
|
|
|
|
virtual void on_init()
|
|
|
|
{
|
|
|
|
start();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ID finalization
|
|
|
|
virtual void on_stop()
|
|
|
|
{
|
2016-04-25 10:49:12 +00:00
|
|
|
m_thread->join();
|
2016-02-01 21:55:43 +00:00
|
|
|
}
|
|
|
|
|
2015-11-26 08:06:29 +00:00
|
|
|
// Get thread_ctrl
|
2016-04-25 10:49:12 +00:00
|
|
|
const thread_ctrl* operator->() const
|
2016-02-01 21:55:43 +00:00
|
|
|
{
|
|
|
|
return m_thread.get();
|
|
|
|
}
|
2015-11-26 08:06:29 +00:00
|
|
|
|
2016-04-25 10:49:12 +00:00
|
|
|
// Lock mutex, notify condition variable
|
|
|
|
void lock_notify() const
|
|
|
|
{
|
|
|
|
m_thread->lock_notify();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Notify condition variable
|
|
|
|
void notify() const
|
2016-02-01 21:55:43 +00:00
|
|
|
{
|
2016-04-25 10:49:12 +00:00
|
|
|
m_thread->notify();
|
2016-02-01 21:55:43 +00:00
|
|
|
}
|
2014-10-17 20:13:25 +00:00
|
|
|
};
|
|
|
|
|
2015-11-26 08:06:29 +00:00
|
|
|
// Wrapper for named thread, joins automatically in the destructor, can only be used in function scope
|
2016-02-01 21:55:43 +00:00
|
|
|
class scope_thread final
|
2015-07-03 23:22:24 +00:00
|
|
|
{
|
2015-11-26 08:06:29 +00:00
|
|
|
std::shared_ptr<thread_ctrl> m_thread;
|
2015-07-03 23:22:24 +00:00
|
|
|
|
|
|
|
public:
|
2015-11-26 08:06:29 +00:00
|
|
|
template<typename N, typename F>
|
2016-02-01 21:55:43 +00:00
|
|
|
scope_thread(N&& name, F&& func)
|
2015-11-26 08:06:29 +00:00
|
|
|
: m_thread(thread_ctrl::spawn(std::forward<N>(name), std::forward<F>(func)))
|
2015-07-03 23:22:24 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-11-26 08:06:29 +00:00
|
|
|
// Deleted copy/move constructors + copy/move operators
|
2016-02-01 21:55:43 +00:00
|
|
|
scope_thread(const scope_thread&) = delete;
|
2015-09-26 20:46:04 +00:00
|
|
|
|
2015-11-26 08:06:29 +00:00
|
|
|
// Destructor with exceptions allowed
|
2016-02-01 21:55:43 +00:00
|
|
|
~scope_thread() noexcept(false)
|
2015-07-03 23:22:24 +00:00
|
|
|
{
|
2015-11-26 08:06:29 +00:00
|
|
|
m_thread->join();
|
2015-07-03 23:22:24 +00:00
|
|
|
}
|
|
|
|
};
|