Improvements in threading/windows module, threading/common module
This commit is contained in:
parent
4aad26efa7
commit
5c02c56c5b
@ -14,7 +14,7 @@ project(networks_1 LANGUAGES CXX)
|
|||||||
set(CMP0155 NEW)
|
set(CMP0155 NEW)
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(CMAKE_CXX_SCAN_FOR_MODULES ON)
|
set(CMAKE_CXX_SCAN_FOR_MODULES ON)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED YES)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_CXX_MODULE_STD 1)
|
set(CMAKE_CXX_MODULE_STD 1)
|
||||||
|
|
||||||
add_subdirectory(modules/exceptions)
|
add_subdirectory(modules/exceptions)
|
||||||
|
|||||||
@ -5,6 +5,8 @@ target_sources(
|
|||||||
|
|
||||||
PUBLIC
|
PUBLIC
|
||||||
FILE_SET cxx_modules TYPE CXX_MODULES FILES
|
FILE_SET cxx_modules TYPE CXX_MODULES FILES
|
||||||
|
src/common.cppm
|
||||||
|
src/thread_routine.cppm
|
||||||
src/windows.cppm
|
src/windows.cppm
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
48
modules/threads/src/common.cppm
Normal file
48
modules/threads/src/common.cppm
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
export module ru.landgrafhomyak.BGTU.networks_1.threads;
|
||||||
|
import std;
|
||||||
|
export import :thread_routine;
|
||||||
|
import :impl;
|
||||||
|
|
||||||
|
|
||||||
|
namespace LdH {
|
||||||
|
export class ThreadController {
|
||||||
|
private:
|
||||||
|
LdH::_NativeThreads::ThreadController _value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ThreadController() = default;
|
||||||
|
|
||||||
|
ThreadController(LdH::ThreadController &) = delete;
|
||||||
|
|
||||||
|
ThreadController(LdH::ThreadController const &) = delete;
|
||||||
|
|
||||||
|
ThreadController(LdH::ThreadController &&other) noexcept : _value{std::move(other._value)} {
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(LdH::ThreadController &&other) noexcept {
|
||||||
|
this->_value = std::move(other._value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void join() {
|
||||||
|
this->_value.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy() {
|
||||||
|
this->_value.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ThreadController(LdH::_NativeThreads::ThreadController &&value) : _value{std::move(value)} {
|
||||||
|
};
|
||||||
|
|
||||||
|
friend
|
||||||
|
LdH::ThreadController fork(std::string &&name, LdH::ThreadRoutine auto &&routine);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export LdH::ThreadController fork(std::string &&name, ThreadRoutine auto &&routine) {
|
||||||
|
return LdH::ThreadController{LdH::_NativeThreads::fork(std::move(name), std::move(routine))};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module:private;
|
||||||
8
modules/threads/src/thread_routine.cppm
Normal file
8
modules/threads/src/thread_routine.cppm
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export module ru.landgrafhomyak.BGTU.networks_1.threads:thread_routine;
|
||||||
|
import std;
|
||||||
|
|
||||||
|
namespace LdH {
|
||||||
|
export
|
||||||
|
template<class lambda_t>
|
||||||
|
concept ThreadRoutine = std::invocable<lambda_t> && std::same_as<std::invoke_result_t<lambda_t>, void> && std::movable<lambda_t> && std::destructible<lambda_t>;
|
||||||
|
}
|
||||||
@ -1,19 +1,22 @@
|
|||||||
module;
|
module;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
export module ru.landgrafhomyak.BGTU.networks_1.threads;
|
export module ru.landgrafhomyak.BGTU.networks_1.threads:impl;
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
|
|
||||||
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
|
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
|
||||||
import ru.landgrafhomyak.BGTU.networks_1.exceptions.windows;
|
import ru.landgrafhomyak.BGTU.networks_1.exceptions.windows;
|
||||||
|
import :thread_routine;
|
||||||
|
|
||||||
|
namespace LdH::_NativeThreads {
|
||||||
namespace LdH {
|
|
||||||
enum class _thread_state {
|
enum class _thread_state {
|
||||||
_thread_state_UNINITIALIZED,
|
_thread_state_UNINITIALIZED,
|
||||||
_thread_state_RUNNING,
|
_thread_state_RUNNING,
|
||||||
|
_thread_state_JOINING,
|
||||||
_thread_state_JOINED,
|
_thread_state_JOINED,
|
||||||
_thread_state_DESTROYED,
|
_thread_state_DESTROYED,
|
||||||
_thread_state_MOVED
|
_thread_state_MOVED
|
||||||
@ -21,28 +24,30 @@ namespace LdH {
|
|||||||
|
|
||||||
using _thread_state::_thread_state_UNINITIALIZED;
|
using _thread_state::_thread_state_UNINITIALIZED;
|
||||||
using _thread_state::_thread_state_RUNNING;
|
using _thread_state::_thread_state_RUNNING;
|
||||||
|
using _thread_state::_thread_state_JOINING;
|
||||||
using _thread_state::_thread_state_JOINED;
|
using _thread_state::_thread_state_JOINED;
|
||||||
using _thread_state::_thread_state_DESTROYED;
|
using _thread_state::_thread_state_DESTROYED;
|
||||||
using _thread_state::_thread_state_MOVED;
|
using _thread_state::_thread_state_MOVED;
|
||||||
|
|
||||||
|
|
||||||
export
|
|
||||||
template<class lambda_t>
|
|
||||||
concept ThreadRoutine = std::invocable<lambda_t> && std::same_as<std::invoke_result_t<lambda_t>, void> && std::movable<lambda_t>;
|
|
||||||
|
|
||||||
export class ThreadController;
|
export class ThreadController;
|
||||||
|
|
||||||
export ThreadController fork(std::string name, ThreadRoutine auto);
|
export ThreadController fork(std::string &&name, ThreadRoutine auto &&);
|
||||||
|
|
||||||
export class ThreadController {
|
export class ThreadController {
|
||||||
private:
|
private:
|
||||||
_thread_state state;
|
std::atomic<_thread_state> state;
|
||||||
HANDLE hThread;
|
HANDLE hThread;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ThreadController();
|
ThreadController();
|
||||||
|
|
||||||
ThreadController(ThreadController &&other);
|
ThreadController(ThreadController &) = delete;
|
||||||
|
|
||||||
|
ThreadController(ThreadController const &) = delete;
|
||||||
|
|
||||||
|
ThreadController(ThreadController &&other) noexcept;
|
||||||
|
|
||||||
|
void operator=(ThreadController &&other) noexcept;
|
||||||
|
|
||||||
void join();
|
void join();
|
||||||
|
|
||||||
@ -80,16 +85,21 @@ namespace LdH {
|
|||||||
};
|
};
|
||||||
|
|
||||||
friend
|
friend
|
||||||
ThreadController fork(std::string name, ThreadRoutine auto);
|
ThreadController fork(std::string &&, ThreadRoutine auto &&);
|
||||||
|
|
||||||
|
[[nodiscard]] _thread_state _cas_state(_thread_state expected, _thread_state next) {
|
||||||
|
this->state.compare_exchange_strong(expected, next);
|
||||||
|
return expected;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export LdH::ThreadController LdH::fork(std::string name, LdH::ThreadRoutine auto routine) {
|
export LdH::_NativeThreads::ThreadController LdH::_NativeThreads::fork(std::string &&name, LdH::ThreadRoutine auto &&routine) {
|
||||||
using thread_routine_t = decltype(routine);
|
using thread_routine_t = std::remove_reference_t<decltype(routine)>;
|
||||||
|
|
||||||
void *notifier_expected = nullptr;
|
void *notifier_expected = nullptr;
|
||||||
|
|
||||||
LdH::ThreadController::_initializer<thread_routine_t> initializer{
|
LdH::_NativeThreads::ThreadController::_initializer<thread_routine_t> initializer{
|
||||||
.notifier = nullptr,
|
.notifier = nullptr,
|
||||||
.name = std::move(name),
|
.name = std::move(name),
|
||||||
.thread_routine = std::move(routine)
|
.thread_routine = std::move(routine)
|
||||||
@ -97,7 +107,7 @@ export LdH::ThreadController LdH::fork(std::string name, LdH::ThreadRoutine auto
|
|||||||
HANDLE hThread = CreateThread(
|
HANDLE hThread = CreateThread(
|
||||||
nullptr,
|
nullptr,
|
||||||
0,
|
0,
|
||||||
(LPTHREAD_START_ROUTINE) &LdH::ThreadController::_kernel<thread_routine_t>,
|
(LPTHREAD_START_ROUTINE) &LdH::_NativeThreads::ThreadController::_kernel<thread_routine_t>,
|
||||||
&initializer,
|
&initializer,
|
||||||
0u,
|
0u,
|
||||||
nullptr
|
nullptr
|
||||||
@ -115,29 +125,42 @@ export LdH::ThreadController LdH::fork(std::string name, LdH::ThreadRoutine auto
|
|||||||
return ThreadController{_thread_state_RUNNING, hThread};
|
return ThreadController{_thread_state_RUNNING, hThread};
|
||||||
}
|
}
|
||||||
|
|
||||||
module : private;
|
LdH::_NativeThreads::ThreadController::ThreadController() : state{_thread_state_UNINITIALIZED}, hThread{nullptr} {
|
||||||
|
|
||||||
LdH::ThreadController::ThreadController() : state{_thread_state_UNINITIALIZED}, hThread{nullptr} {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LdH::ThreadController::ThreadController(LdH::ThreadController &&other) : state{other.state}, hThread{other.hThread} {
|
LdH::_NativeThreads::ThreadController::ThreadController(LdH::_NativeThreads::ThreadController &&other) noexcept : state{other.state.exchange(_thread_state_MOVED)}, hThread{other.hThread} {
|
||||||
other.hThread = nullptr;
|
other.hThread = nullptr;
|
||||||
other.state = _thread_state_DESTROYED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LdH::ThreadController::join() {
|
void LdH::_NativeThreads::ThreadController::operator=(ThreadController &&other) noexcept {
|
||||||
switch (this->state) {
|
switch (this->state.load()) {
|
||||||
case _thread_state_UNINITIALIZED:
|
case _thread_state_UNINITIALIZED:
|
||||||
throw Exception{"Variable not initialized"};
|
case _thread_state_MOVED:
|
||||||
|
case _thread_state_DESTROYED:
|
||||||
|
break;
|
||||||
|
case _thread_state_RUNNING:
|
||||||
|
case _thread_state_JOINING:
|
||||||
|
case _thread_state_JOINED:
|
||||||
|
throw LdH::Exception{"Variable already initialized"};
|
||||||
|
}
|
||||||
|
new(this)ThreadController{std::move(other)};
|
||||||
|
}
|
||||||
|
|
||||||
|
void LdH::_NativeThreads::ThreadController::join() {
|
||||||
|
switch (this->_cas_state(_thread_state_RUNNING, _thread_state_JOINING)) {
|
||||||
|
case _thread_state_UNINITIALIZED:
|
||||||
|
throw LdH::Exception{"Variable not initialized"};
|
||||||
case _thread_state_RUNNING:
|
case _thread_state_RUNNING:
|
||||||
break;
|
break;
|
||||||
|
case _thread_state_JOINING:
|
||||||
case _thread_state_JOINED:
|
case _thread_state_JOINED:
|
||||||
throw Exception{"Thread already joined"};
|
throw LdH::Exception{"Thread already joined"};
|
||||||
case _thread_state_DESTROYED:
|
case _thread_state_DESTROYED:
|
||||||
throw Exception{"Thread already destroyed"};
|
throw LdH::Exception{"Thread already destroyed"};
|
||||||
case _thread_state_MOVED:
|
case _thread_state_MOVED:
|
||||||
throw Exception{"Content of this variable was moved to another variable"};
|
throw LdH::Exception{"Content of this variable was moved to another variable"};
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -149,42 +172,45 @@ void LdH::ThreadController::join() {
|
|||||||
case WAIT_ABANDONED:
|
case WAIT_ABANDONED:
|
||||||
throw LdH::Exception{"Unexpected return WAIT_ABANDONED of WaitForSingleObject"};
|
throw LdH::Exception{"Unexpected return WAIT_ABANDONED of WaitForSingleObject"};
|
||||||
case WAIT_OBJECT_0:
|
case WAIT_OBJECT_0:
|
||||||
this->state = _thread_state_JOINED;
|
this->state.store(_thread_state_JOINED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LdH::ThreadController::destroy() {
|
void LdH::_NativeThreads::ThreadController::destroy() {
|
||||||
switch (this->state) {
|
switch (this->_cas_state(_thread_state_JOINED, _thread_state_DESTROYED)) {
|
||||||
case _thread_state_UNINITIALIZED:
|
case _thread_state_UNINITIALIZED:
|
||||||
throw Exception{"Variable not initialized"};
|
throw LdH::Exception{"Variable not initialized"};
|
||||||
case _thread_state_RUNNING:
|
case _thread_state_RUNNING:
|
||||||
throw Exception{"Thread not finished yet"};
|
case _thread_state_JOINING:
|
||||||
|
throw LdH::Exception{"Thread not finished yet"};
|
||||||
case _thread_state_JOINED:
|
case _thread_state_JOINED:
|
||||||
break;
|
break;
|
||||||
case _thread_state_DESTROYED:
|
case _thread_state_DESTROYED:
|
||||||
throw Exception{"Thread already destroyed"};
|
throw LdH::Exception{"Thread already destroyed"};
|
||||||
case _thread_state_MOVED:
|
case _thread_state_MOVED:
|
||||||
throw Exception{"Content of this variable was moved to another variable"};
|
throw LdH::Exception{"Content of this variable was moved to another variable"};
|
||||||
}
|
}
|
||||||
if (0 == CloseHandle(this->hThread))
|
if (0 == CloseHandle(this->hThread))
|
||||||
LdH::throwFromLastWindowsErr();
|
LdH::throwFromLastWindowsErr();
|
||||||
this->state = _thread_state_DESTROYED;
|
|
||||||
this->hThread = nullptr;
|
this->hThread = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
LdH::ThreadController::~ThreadController() noexcept(false) {
|
LdH::_NativeThreads::ThreadController::~ThreadController() noexcept(false) {
|
||||||
switch (this->state) {
|
switch (this->state.load()) {
|
||||||
case _thread_state_UNINITIALIZED:
|
case _thread_state_UNINITIALIZED:
|
||||||
break;
|
break;
|
||||||
case _thread_state_RUNNING:
|
case _thread_state_RUNNING:
|
||||||
throw Exception{"Thread not finished yet"};
|
case _thread_state_JOINING:
|
||||||
|
throw LdH::Exception{"Thread not finished yet"};
|
||||||
case _thread_state_JOINED:
|
case _thread_state_JOINED:
|
||||||
throw Exception{"Thread not destroyed yet"};
|
throw LdH::Exception{"Thread not destroyed yet"};
|
||||||
case _thread_state_DESTROYED:
|
case _thread_state_DESTROYED:
|
||||||
break;
|
break;
|
||||||
case _thread_state_MOVED:
|
case _thread_state_MOVED:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user