Improvements in threading/windows module, threading/common module

This commit is contained in:
Andrew Golovashevich 2025-10-27 07:29:37 +03:00
parent 4aad26efa7
commit 5c02c56c5b
5 changed files with 124 additions and 40 deletions

View File

@ -14,7 +14,7 @@ project(networks_1 LANGUAGES CXX)
set(CMP0155 NEW)
set(CMAKE_CXX_STANDARD 23)
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)
add_subdirectory(modules/exceptions)

View File

@ -5,6 +5,8 @@ target_sources(
PUBLIC
FILE_SET cxx_modules TYPE CXX_MODULES FILES
src/common.cppm
src/thread_routine.cppm
src/windows.cppm
)

View 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;

View 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>;
}

View File

@ -1,19 +1,22 @@
module;
#ifdef _WIN32
#include <Windows.h>
export module ru.landgrafhomyak.BGTU.networks_1.threads;
export module ru.landgrafhomyak.BGTU.networks_1.threads:impl;
import std;
import ru.landgrafhomyak.BGTU.networks_1.exceptions;
import ru.landgrafhomyak.BGTU.networks_1.exceptions.windows;
import :thread_routine;
namespace LdH {
namespace LdH::_NativeThreads {
enum class _thread_state {
_thread_state_UNINITIALIZED,
_thread_state_RUNNING,
_thread_state_JOINING,
_thread_state_JOINED,
_thread_state_DESTROYED,
_thread_state_MOVED
@ -21,28 +24,30 @@ namespace LdH {
using _thread_state::_thread_state_UNINITIALIZED;
using _thread_state::_thread_state_RUNNING;
using _thread_state::_thread_state_JOINING;
using _thread_state::_thread_state_JOINED;
using _thread_state::_thread_state_DESTROYED;
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 ThreadController fork(std::string name, ThreadRoutine auto);
export ThreadController fork(std::string &&name, ThreadRoutine auto &&);
export class ThreadController {
private:
_thread_state state;
std::atomic<_thread_state> state;
HANDLE hThread;
public:
ThreadController();
ThreadController(ThreadController &&other);
ThreadController(ThreadController &) = delete;
ThreadController(ThreadController const &) = delete;
ThreadController(ThreadController &&other) noexcept;
void operator=(ThreadController &&other) noexcept;
void join();
@ -80,16 +85,21 @@ namespace LdH {
};
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) {
using thread_routine_t = decltype(routine);
export LdH::_NativeThreads::ThreadController LdH::_NativeThreads::fork(std::string &&name, LdH::ThreadRoutine auto &&routine) {
using thread_routine_t = std::remove_reference_t<decltype(routine)>;
void *notifier_expected = nullptr;
LdH::ThreadController::_initializer<thread_routine_t> initializer{
LdH::_NativeThreads::ThreadController::_initializer<thread_routine_t> initializer{
.notifier = nullptr,
.name = std::move(name),
.thread_routine = std::move(routine)
@ -97,7 +107,7 @@ export LdH::ThreadController LdH::fork(std::string name, LdH::ThreadRoutine auto
HANDLE hThread = CreateThread(
nullptr,
0,
(LPTHREAD_START_ROUTINE) &LdH::ThreadController::_kernel<thread_routine_t>,
(LPTHREAD_START_ROUTINE) &LdH::_NativeThreads::ThreadController::_kernel<thread_routine_t>,
&initializer,
0u,
nullptr
@ -115,29 +125,42 @@ export LdH::ThreadController LdH::fork(std::string name, LdH::ThreadRoutine auto
return ThreadController{_thread_state_RUNNING, hThread};
}
module : private;
LdH::ThreadController::ThreadController() : state{_thread_state_UNINITIALIZED}, hThread{nullptr} {
LdH::_NativeThreads::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.state = _thread_state_DESTROYED;
}
void LdH::ThreadController::join() {
switch (this->state) {
void LdH::_NativeThreads::ThreadController::operator=(ThreadController &&other) noexcept {
switch (this->state.load()) {
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:
break;
case _thread_state_JOINING:
case _thread_state_JOINED:
throw Exception{"Thread already joined"};
throw LdH::Exception{"Thread already joined"};
case _thread_state_DESTROYED:
throw Exception{"Thread already destroyed"};
throw LdH::Exception{"Thread already destroyed"};
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) {
@ -149,42 +172,45 @@ void LdH::ThreadController::join() {
case WAIT_ABANDONED:
throw LdH::Exception{"Unexpected return WAIT_ABANDONED of WaitForSingleObject"};
case WAIT_OBJECT_0:
this->state = _thread_state_JOINED;
this->state.store(_thread_state_JOINED);
return;
}
}
}
void LdH::ThreadController::destroy() {
switch (this->state) {
void LdH::_NativeThreads::ThreadController::destroy() {
switch (this->_cas_state(_thread_state_JOINED, _thread_state_DESTROYED)) {
case _thread_state_UNINITIALIZED:
throw Exception{"Variable not initialized"};
throw LdH::Exception{"Variable not initialized"};
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:
break;
case _thread_state_DESTROYED:
throw Exception{"Thread already destroyed"};
throw LdH::Exception{"Thread already destroyed"};
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))
LdH::throwFromLastWindowsErr();
this->state = _thread_state_DESTROYED;
this->hThread = nullptr;
}
LdH::ThreadController::~ThreadController() noexcept(false) {
switch (this->state) {
LdH::_NativeThreads::ThreadController::~ThreadController() noexcept(false) {
switch (this->state.load()) {
case _thread_state_UNINITIALIZED:
break;
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:
throw Exception{"Thread not destroyed yet"};
throw LdH::Exception{"Thread not destroyed yet"};
case _thread_state_DESTROYED:
break;
case _thread_state_MOVED:
break;
}
}
#endif