Browse Source

支持编译为动态库,支持安装脚本

3.0.0
tearshark 2 years ago
parent
commit
54c0ad32b9

+ 2
- 0
.gitignore View File

@@ -12,3 +12,5 @@ private
bin
out
/CMakeSettings.json
install
lib

+ 21
- 12
CMakeLists.txt View File

@@ -54,7 +54,8 @@ option(OPT_DEBUG_COUNTER "Debug objects count" OFF)
option(OPT_KEEP_REAL_SIZE "Keep real size in queue" OFF)
option(OPT_DISABLE_MULT_THREAD "Disable multi-threaded scheduler" OFF)
option(OPT_USE_MIMALLOC "Use mimalloc" OFF)
option(OPT_DYNAMIC_LIBRARY "Use shared library" OFF)
option(OPT_DYNAMIC_LIBRARY "Use shared library" ON)
option(CMAKE_ENABLE_UNIT_TEST "Enable unit test" OFF)
if (UNIX)
if(OPT_USE_MIMALLOC)
@@ -92,10 +93,6 @@ endif()
if(OPT_DISABLE_MULT_THREAD)
set(RESUMEF_DISABLE_MULT_THREAD 1)
endif()
if(OPT_DYNAMIC_LIBRARY)
set(RESUMEF_USE_SHARD_LIBRARY 1)
add_compile_definitions("-DRESUMEF_DYNAMIC_EXPORTS=1")
endif()
configure_file(
${CMAKE_SOURCE_DIR}/config.h.in
@@ -107,6 +104,7 @@ file(GLOB_RECURSE HEADER_FILES ${CMAKE_SOURCE_DIR}/include/*.*)
file(GLOB_RECURSE SOURCE_FILES ${CMAKE_SOURCE_DIR}/source/*.*)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
if(OPT_DYNAMIC_LIBRARY)
@@ -114,28 +112,39 @@ if(OPT_DYNAMIC_LIBRARY)
${HEADER_FILES}
${SOURCE_FILES}
)
target_compile_definitions(${PROJECT_NAME}
PRIVATE LIBRF_DYNAMIC_EXPORTS=1
)
else()
add_library(${PROJECT_NAME} STATIC
${HEADER_FILES}
${SOURCE_FILES}
)
target_compile_definitions(${PROJECT_NAME}
PRIVATE LIBRF_USE_STATIC_LIBRARY=1
)
endif()
target_include_directories(${PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)
include_directories(
${CMAKE_SOURCE_DIR}/modern_cb
)
if(OPT_USE_MIMALLOC)
set(LIB_MIMALLOC, "mimalloc")
else()
set(LIB_MIMALLOC, "")
endif()
add_subdirectory(tutorial)
#add_subdirectory(benchmark)
if(CMAKE_ENABLE_UNIT_TEST)
include_directories(
${CMAKE_SOURCE_DIR}/modern_cb
)
add_subdirectory(tutorial)
#add_subdirectory(benchmark)
endif()
include(${CMAKE_SOURCE_DIR}/cmake/install.cmake)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/include/librf DESTINATION include)

+ 2
- 0
Config.cmake.in View File

@@ -0,0 +1,2 @@
include(${CMAKE_CURRENT_LIST_DIR}/SelectDynamicLibrary.cmake)
select_dynamic_library(librf librf/librf.h)

+ 161
- 0
cmake/SelectDynamicLibrary.cmake View File

@@ -0,0 +1,161 @@
include(SelectLibraryConfigurations)

macro(_acl_copy_dynamic_library_build_type basename build_type)

if(${build_type} STREQUAL "Debug")
set(_acl_build_type_dir "Debug")
set(_acl_runtime_output_dir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG})
elseif(${build_type} STREQUAL "Release")
set(_acl_build_type_dir "Release")
set(_acl_runtime_output_dir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE})
elseif(${build_type} STREQUAL "MinSizeRel")
set(_acl_build_type_dir "Release")
set(_acl_runtime_output_dir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL})
elseif(${build_type} STREQUAL "RelWithDebInfo")
set(_acl_build_type_dir "Release")
set(_acl_runtime_output_dir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO})
endif()
#message(STATUS "_acl_build_type_dir=${CMAKE_CURRENT_LIST_DIR}/../lib/${CMAKE_CXX_PLATFORM_ID}/${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}-${_acl_build_type_dir}")
#message(STATUS "_acl_runtime_output_dir=${_acl_runtime_output_dir}")

find_file(_acl_${basename}_dynamic_binary
NAMES "Acl.${basename}.dll" "Acl.${basename}.so"
PATHS
${CMAKE_CURRENT_LIST_DIR}/../bin/${CMAKE_CXX_PLATFORM_ID}/${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}-${_acl_build_type_dir}
NO_DEFAULT_PATH
)
if(NOT _acl_${basename}_dynamic_binary)
find_file(_acl_${basename}_dynamic_binary
NAMES "${basename}.dll" "${basename}.so"
PATHS
${CMAKE_CURRENT_LIST_DIR}/../bin/${CMAKE_CXX_PLATFORM_ID}/${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}-${_acl_build_type_dir}
NO_DEFAULT_PATH
)
endif()

#message(STATUS "_acl_runtime_dynamic_binary=${_acl_runtime_dynamic_binary}")

if(_acl_${basename}_dynamic_binary)
file(INSTALL ${_acl_${basename}_dynamic_binary} DESTINATION ${_acl_runtime_output_dir})
endif()

unset(_acl_build_type_dir)
unset(_acl_runtime_output_dir)
unset(_acl_${basename}_dynamic_binary CACHE)
endmacro(_acl_copy_dynamic_library_build_type)

macro(_acl_copy_dynamic_library basename)

if(DEFINED CMAKE_CONFIGURATION_TYPES)
foreach(build_type ${CMAKE_CONFIGURATION_TYPES})
_acl_copy_dynamic_library_build_type(${basename} ${build_type})
endforeach(build_type)
elseif(DEFINED CMAKE_BUILD_TYPE)
_acl_copy_dynamic_library_build_type(${basename} ${CMAKE_BUILD_TYPE})
else()
_acl_copy_dynamic_library_build_type(${basename} "Release")
endif()

endmacro(_acl_copy_dynamic_library)


macro(select_dynamic_library basename header)
#message(STATUS "basename=${basename}")
#message(STATUS "header=${header}")

# 如果已经找到了 basename 指定的模块,则只做拷贝运行时的动态库的工作
#message(STATUS "${basename}_FOUND=${${basename}_FOUND}")
if(${basename}_FOUND)
_acl_copy_dynamic_library(${basename})
return()
endif()



# 查找头文件所在的路径
find_path(${basename}_INCLUDE_DIR ${header}
${CMAKE_CURRENT_LIST_DIR}/../include
NO_DEFAULT_PATH
)

# 查找调试版本的库文件所在路径
find_library("${basename}_LIBRARY_DEBUG"
NAMES "Acl.${basename}"
PATHS
${CMAKE_CURRENT_LIST_DIR}/../lib/${CMAKE_CXX_PLATFORM_ID}/${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}-Debug
NO_DEFAULT_PATH
)
if(NOT ${basename}_LIBRARY_DEBUG)
find_library("${basename}_LIBRARY_DEBUG"
NAMES "${basename}"
PATHS
${CMAKE_CURRENT_LIST_DIR}/../lib/${CMAKE_CXX_PLATFORM_ID}/${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}-Debug
NO_DEFAULT_PATH
)
endif()

# 查找发行版本的库文件所在路径
find_library("${basename}_LIBRARY_RELEASE"
NAMES "Acl.${basename}"
PATHS
${CMAKE_CURRENT_LIST_DIR}/../lib/${CMAKE_CXX_PLATFORM_ID}/${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}-Release
NO_DEFAULT_PATH
)
if(NOT ${basename}_LIBRARY_RELEASE)
find_library("${basename}_LIBRARY_RELEASE"
NAMES "${basename}"
PATHS
${CMAKE_CURRENT_LIST_DIR}/../lib/${CMAKE_CXX_PLATFORM_ID}/${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}-Release
NO_DEFAULT_PATH
)
endif()

# 使用cmake内置的 select_library_configurations 函数生成 ${basename}_LIBRARY 字段
select_library_configurations(${basename})



set(${basename}_FOUND FALSE)
if(${basename}_LIBRARY AND ${basename}_INCLUDE_DIR)

set(${basename}_FOUND TRUE)
if(NOT ${basename}_DIR)
set(${basename}_DIR ${CMAKE_CURRENT_LIST_DIR})
endif()

# 做拷贝运行时的动态库到目标目录
_acl_copy_dynamic_library(${basename})

# 创建 basename 指定的导入接口模块
if(NOT TARGET Acl::${basename})

add_library(Acl::${basename} UNKNOWN IMPORTED)
set_target_properties(Acl::${basename} PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${${basename}_INCLUDE_DIR}")

set_property(TARGET Acl::${basename} APPEND PROPERTY
IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(Acl::${basename} PROPERTIES
IMPORTED_LOCATION_RELEASE "${${basename}_LIBRARY_RELEASE}")

set_property(TARGET Acl::${basename} APPEND PROPERTY
IMPORTED_CONFIGURATIONS DEBUG)
set_target_properties(Acl::${basename} PROPERTIES
IMPORTED_LOCATION_DEBUG "${${basename}_LIBRARY_DEBUG}")
endif()
endif()



mark_as_advanced(${basename}_DIR)
mark_as_advanced(${basename}_LIBRARY)
mark_as_advanced(${basename}_INCLUDE_DIR)

#message(STATUS "${basename}_DIR=${${basename}_DIR}")
#message(STATUS "${basename}_LIBRARY=${${basename}_LIBRARY}")
#message(STATUS "${basename}_LIBRARY_DEBUG=${${basename}_LIBRARY_DEBUG}")
#message(STATUS "${basename}_LIBRARY_RELEASE=${${basename}_LIBRARY_RELEASE}")
#message(STATUS "${basename}_INCLUDE_DIR=${${basename}_INCLUDE_DIR}")

endmacro(select_dynamic_library)

+ 45
- 0
cmake/install.cmake View File

@@ -0,0 +1,45 @@

# Configuration
# Used by cmake to find_package(xxx)
set(PROJECT_CONFIG "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake")

# Add definitions for targets
# Values:
# * Debug: -Dxxx_DEBUG=1
# * Release: -Dxxx_DEBUG=0
# * other: -Dxxx_DEBUG=0
target_compile_definitions(${PROJECT_NAME} PUBLIC ${PROJECT_NAME}_DEBUG=$<CONFIG:Debug>)

# Include module with function 'write_basic_package_version_file'
# Configure 'xxxConfigVersion.cmake'
include(CMakePackageConfigHelpers)
write_basic_package_version_file(${VERSION_CONFIG} VERSION ${PACKAGE_VERSION}
COMPATIBILITY SameMajorVersion)

# Configure 'xxxConfig.cmake'
configure_package_config_file(Config.cmake.in ${PROJECT_CONFIG}
INSTALL_DESTINATION cmake/${PROJECT_NAME})

# Targets:
# * <prefix>/lib/Windows/x64-Debug/xxx.lib
# * <prefix>/bin/Windows/x64-Debug/xxx.dll
set(INSTALL_TARGET_PREFIX "${CMAKE_CXX_PLATFORM_ID}/${CMAKE_CXX_COMPILER_ARCHITECTURE_ID}")
install(TARGETS ${PROJECT_NAME}
CONFIGURATIONS Debug
LIBRARY DESTINATION "lib/${INSTALL_TARGET_PREFIX}-Debug"
ARCHIVE DESTINATION "lib/${INSTALL_TARGET_PREFIX}-Debug"
RUNTIME DESTINATION "bin/${INSTALL_TARGET_PREFIX}-Debug"
)
# * <prefix>/lib/Windows/x64-Release/xxx.lib
# * <prefix>/bin/Windows/x64-Release/xxx.dll
install(TARGETS ${PROJECT_NAME}
CONFIGURATIONS Release RelWithDebInfo MinSizeRel
LIBRARY DESTINATION "lib/${INSTALL_TARGET_PREFIX}-Release"
ARCHIVE DESTINATION "lib/${INSTALL_TARGET_PREFIX}-Release"
RUNTIME DESTINATION "bin/${INSTALL_TARGET_PREFIX}-Release"
)

# Config
# * <prefix>/cmake/xxxConfig.cmake
# * <prefix>/cmake/xxxConfigVersion.cmake
install(FILES ${PROJECT_CONFIG} DESTINATION cmake)

+ 1
- 0
include/librf/librf.h View File

@@ -71,6 +71,7 @@ extern "C" void _coro_resume_block();

#include "src/def.h"
#include "src/macro_def.inl"
#include "src/exception.inl"
#include "src/counted_ptr.h"
#include "src/type_traits.inl"
#include "src/type_concept.inl"

+ 0
- 8
include/librf/src/def.h View File

@@ -53,12 +53,6 @@ namespace librf
* @brief 版本号。
*/
constexpr size_t _Version = LIB_RESUMEF_VERSION;

/**
* @brief 获得当前线程下的调度器。
*/
scheduler_t* this_scheduler();

}

#ifndef DOXYGEN_SKIP_PROPERTY
@@ -102,6 +96,4 @@ namespace librf
}
}

#include "exception.inl"

#endif //DOXYGEN_SKIP_PROPERTY

+ 3
- 3
include/librf/src/event_v2.h View File

@@ -23,18 +23,18 @@ namespace librf
* @brief 构造一个事件。
* @param initially 初始是否触发一次信号。
*/
event_t(bool initially = false);
LIBRF_API event_t(bool initially = false);

/**
* @brief 构造一个无效的事件。
* @details 如果用于后续保存另外一个事件,则应当使用此构造函数,便于节省一次不必要的内部初始化。
*/
event_t(std::adopt_lock_t);
LIBRF_API event_t(std::adopt_lock_t);

/**
* @brief 采用shared_ptr<>来保存内部的事件实现。故不必担心正在被等待的协程,因为事件提前销毁而出现异常。
*/
~event_t();
LIBRF_API ~event_t();

/**
* @brief 向所有正在等待的协程触发一次信号。

+ 12
- 12
include/librf/src/event_v2.inl View File

@@ -8,8 +8,8 @@ namespace librf

struct event_v2_impl : public std::enable_shared_from_this<event_v2_impl>
{
event_v2_impl(bool initially) noexcept;
~event_v2_impl();
LIBRF_API event_v2_impl(bool initially) noexcept;
LIBRF_API ~event_v2_impl();

bool is_signaled() const noexcept
{
@@ -19,8 +19,8 @@ namespace librf
{
_counter.store(0, std::memory_order_release);
}
void signal_all() noexcept;
void signal() noexcept;
LIBRF_API void signal_all() noexcept;
LIBRF_API void signal() noexcept;

public:
static constexpr bool USE_SPINLOCK = true;
@@ -62,8 +62,8 @@ namespace librf

struct state_event_base_t : public state_base_t
{
virtual void resume() override;
virtual bool has_handler() const noexcept override;
LIBRF_API virtual void resume() override;
LIBRF_API virtual bool has_handler() const noexcept override;

virtual void on_cancel() noexcept = 0;
virtual bool on_notify(event_v2_impl* eptr) = 0;
@@ -103,9 +103,9 @@ namespace librf
: _value(&val)
{}

virtual void on_cancel() noexcept override;
virtual bool on_notify(event_v2_impl* eptr) override;
virtual bool on_timeout() override;
LIBRF_API virtual void on_cancel() noexcept override;
LIBRF_API virtual bool on_notify(event_v2_impl* eptr) override;
LIBRF_API virtual bool on_timeout() override;
protected:
//_value引用awaitor保存的值,这样可以尽可能减少创建state的可能。而不必进入没有state就没有value实体被用于返回。
//在调用on_notify()或on_timeout()任意之一后,置为nullptr。
@@ -121,9 +121,9 @@ namespace librf
, _value(&val)
{}

virtual void on_cancel() noexcept override;
virtual bool on_notify(event_v2_impl* eptr) override;
virtual bool on_timeout() override;
LIBRF_API virtual void on_cancel() noexcept override;
LIBRF_API virtual bool on_notify(event_v2_impl* eptr) override;
LIBRF_API virtual bool on_timeout() override;

std::atomic<intptr_t> _counter;
protected:

+ 1
- 2
include/librf/src/exception.inl View File

@@ -23,12 +23,11 @@ namespace librf
/**
* @brief 通过错误码获得错误描述字符串。
*/
const char* get_error_string(error_code fe, const char* classname);
LIBRF_API const char* get_error_string(error_code fe, const char* classname);

/**
* @brief 在操作future_t<>时产生的异常。
*/
const char* get_error_string(error_code fe, const char* classname);
struct future_exception : std::logic_error
{
error_code _error;

+ 2
- 2
include/librf/src/macro_def.inl View File

@@ -32,9 +32,9 @@
#endif // unlikely
#endif // defined(__clang__) || defined(__GNUC__)

#ifdef RESUMEF_USE_SHARD_LIBRARY
#ifndef LIBRF_USE_STATIC_LIBRARY
# if _WIN32
# ifdef RESUMEF_DYNAMIC_EXPORTS
# ifdef LIBRF_DYNAMIC_EXPORTS
# define LIBRF_API __declspec(dllexport)
# else //RESUMEF_DYNAMIC_EXPORTS
# define LIBRF_API __declspec(dllimport)

+ 3
- 3
include/librf/src/mutex_v2.h View File

@@ -209,13 +209,13 @@ namespace librf
>
static void unlock(void* unique_address, _Mtxs&... mtxs);

mutex_t();
LIBRF_API mutex_t();

/**
* @brief 构造一个无效的mutex_t。
*/
mutex_t(std::adopt_lock_t) noexcept;
~mutex_t() noexcept;
LIBRF_API mutex_t(std::adopt_lock_t) noexcept;
LIBRF_API ~mutex_t() noexcept;

mutex_t(const mutex_t&) = default;
mutex_t(mutex_t&&) = default;

+ 13
- 13
include/librf/src/mutex_v2.inl View File

@@ -10,15 +10,15 @@ namespace librf
: _value(&val)
{}

virtual void resume() override;
virtual bool has_handler() const noexcept override;
virtual state_base_t* get_parent() const noexcept override;
LIBRF_API virtual void resume() override;
LIBRF_API virtual bool has_handler() const noexcept override;
LIBRF_API virtual state_base_t* get_parent() const noexcept override;

void on_cancel() noexcept;
bool on_notify(mutex_v2_impl* eptr);
bool on_timeout();
LIBRF_API void on_cancel() noexcept;
LIBRF_API bool on_notify(mutex_v2_impl* eptr);
LIBRF_API bool on_timeout();

void add_timeout_timer(std::chrono::system_clock::time_point tp);
LIBRF_API void add_timeout_timer(std::chrono::system_clock::time_point tp);

inline void on_await_suspend(coroutine_handle<> handler, scheduler_t* sch, state_base_t* root) noexcept
{
@@ -44,10 +44,10 @@ namespace librf
return _owner.load(std::memory_order_relaxed);
}

bool try_lock(void* sch); //内部加锁
bool try_lock_until(clock_type::time_point tp, void* sch); //内部加锁
bool unlock(void* sch); //内部加锁
void lock_until_succeed(void* sch); //内部加锁
LIBRF_API bool try_lock(void* sch); //内部加锁
LIBRF_API bool try_lock_until(clock_type::time_point tp, void* sch); //内部加锁
LIBRF_API bool unlock(void* sch); //内部加锁
LIBRF_API void lock_until_succeed(void* sch); //内部加锁
public:
static constexpr bool USE_SPINLOCK = true;

@@ -55,8 +55,8 @@ namespace librf
using state_mutex_ptr = counted_ptr<state_mutex_t>;
using wait_queue_type = std::list<state_mutex_ptr>;

bool try_lock_lockless(void* sch) noexcept; //内部不加锁,加锁由外部来进行
void add_wait_list_lockless(state_mutex_t* state); //内部不加锁,加锁由外部来进行
LIBRF_API bool try_lock_lockless(void* sch) noexcept; //内部不加锁,加锁由外部来进行
LIBRF_API void add_wait_list_lockless(state_mutex_t* state); //内部不加锁,加锁由外部来进行

lock_type _lock; //保证访问本对象是线程安全的
private:

+ 3
- 3
include/librf/src/rf_task.h View File

@@ -16,14 +16,14 @@ namespace librf
*/
struct task_t
{
task_t() noexcept;
virtual ~task_t();
LIBRF_API task_t() noexcept;
LIBRF_API virtual ~task_t();

/**
* @brief 获取stop_source,第一次获取时,会生成一个有效的stop_source。
* @return stop_source
*/
const stop_source & get_stop_source();
LIBRF_API const stop_source & get_stop_source();

/**
* @brief 获取一个跟stop_source绑定的,新的stop_token。

+ 19
- 14
include/librf/src/scheduler.h View File

@@ -2,6 +2,11 @@

namespace librf
{
/**
* @brief 获得当前线程下的调度器。
*/
LIBRF_API scheduler_t* this_scheduler();

/**
* @brief 协程调度器。
* @details librf的设计原则之一,就是要将协程绑定在固定的调度器里执行。
@@ -28,7 +33,7 @@ namespace librf

timer_mgr_ptr _timer;

task_t* new_task(task_t* task);
LIBRF_API task_t* new_task(task_t* task);
//void cancel_all_task_();
public:
/**
@@ -36,13 +41,13 @@ namespace librf
* @details 这是协程调度器提供的主要接口。同一个调度器非线程安全,不可重入。\n
* 调用者要保证此函数始终在同一个线程里调用。
*/
bool run_one_batch();
LIBRF_API bool run_one_batch();

/**
* @brief 循环运行所有的协程,直到所有协程都运行完成。
* @details 通常用于测试代码。
*/
void run_until_notask();
LIBRF_API void run_until_notask();

//void break_all();

@@ -88,24 +93,24 @@ namespace librf
}

#ifndef DOXYGEN_SKIP_PROPERTY
void add_generator(state_base_t* sptr);
void del_final(state_base_t* sptr);
std::unique_ptr<task_t> del_switch(state_base_t* sptr);
void add_switch(std::unique_ptr<task_t> task);
task_t* find_task(state_base_t* sptr) const noexcept;
LIBRF_API void add_generator(state_base_t* sptr);
LIBRF_API void del_final(state_base_t* sptr);
LIBRF_API std::unique_ptr<task_t> del_switch(state_base_t* sptr);
LIBRF_API void add_switch(std::unique_ptr<task_t> task);
LIBRF_API task_t* find_task(state_base_t* sptr) const noexcept;

friend struct local_scheduler_t;
protected:
scheduler_t();
LIBRF_API scheduler_t();
public:
~scheduler_t();
LIBRF_API ~scheduler_t();

scheduler_t(scheduler_t&& right_) = delete;
scheduler_t& operator = (scheduler_t&& right_) = delete;
scheduler_t(const scheduler_t&) = delete;
scheduler_t& operator = (const scheduler_t&) = delete;

static scheduler_t g_scheduler;
LIBRF_API static scheduler_t g_scheduler;
#endif //DOXYGEN_SKIP_PROPERTY
};

@@ -121,17 +126,17 @@ namespace librf
/**
* @brief 尽可能的创建一个线程相关的调度器。
*/
local_scheduler_t();
LIBRF_API local_scheduler_t();

/**
* @brief 将指定的调度器绑定到当前线程上。
*/
local_scheduler_t(scheduler_t & sch) noexcept;
LIBRF_API local_scheduler_t(scheduler_t & sch) noexcept;

/**
* @brief 如果当前线程绑定的调度器由local_scheduler_t所创建,则会销毁调度器,并解绑线程。
*/
~local_scheduler_t();
LIBRF_API ~local_scheduler_t();

local_scheduler_t(local_scheduler_t&& right_) = delete;
local_scheduler_t& operator = (local_scheduler_t&& right_) = delete;

+ 1
- 1
include/librf/src/sleep.h View File

@@ -14,7 +14,7 @@ namespace librf
* @return [co_await] void
* @throw timer_canceled_exception 如果定时器被取消,则抛此异常。
*/
future_t<> sleep_until_(std::chrono::system_clock::time_point tp_, scheduler_t& scheduler_);
LIBRF_API future_t<> sleep_until_(std::chrono::system_clock::time_point tp_, scheduler_t& scheduler_);

/**
* @brief 协程专用的睡眠功能。

+ 16
- 16
include/librf/src/state.h View File

@@ -30,13 +30,13 @@ namespace librf
// 二、没有co_await操作,直接加入到了调度器里,则_coro在初始时为nullptr。调度器需要特殊处理此种情况。
coroutine_handle<> _coro;

virtual ~state_base_t();
LIBRF_API virtual ~state_base_t();
private:
virtual void destroy_deallocate();
LIBRF_API virtual void destroy_deallocate();
public:
virtual void resume() = 0;
virtual bool has_handler() const noexcept = 0;
virtual state_base_t* get_parent() const noexcept;
LIBRF_API virtual state_base_t* get_parent() const noexcept;

void set_scheduler(scheduler_t* sch) noexcept
{
@@ -70,13 +70,13 @@ namespace librf
struct state_generator_t : public state_base_t
{
private:
virtual void destroy_deallocate() override;
LIBRF_API virtual void destroy_deallocate() override;
state_generator_t() = default;
public:
virtual void resume() override;
virtual bool has_handler() const noexcept override;
LIBRF_API virtual void resume() override;
LIBRF_API virtual bool has_handler() const noexcept override;

bool switch_scheduler_await_suspend(scheduler_t* sch);
LIBRF_API bool switch_scheduler_await_suspend(scheduler_t* sch);

void set_initial_suspend(coroutine_handle<> handler) noexcept
{
@@ -89,7 +89,7 @@ namespace librf
return new(_Ptr) state_generator_t();
}
#endif
static state_generator_t* _Alloc_state();
LIBRF_API static state_generator_t* _Alloc_state();
};

/**
@@ -139,10 +139,10 @@ namespace librf
_is_future = !awaitor;
}
public:
virtual void destroy_deallocate() override;
virtual void resume() override;
virtual bool has_handler() const noexcept override;
virtual state_base_t* get_parent() const noexcept override;
LIBRF_API virtual void destroy_deallocate() override;
LIBRF_API virtual void resume() override;
LIBRF_API virtual bool has_handler() const noexcept override;
LIBRF_API virtual state_base_t* get_parent() const noexcept override;

inline bool is_ready() const noexcept
{
@@ -177,7 +177,7 @@ namespace librf
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>>
void future_await_suspend(coroutine_handle<_PromiseT> handler);

bool switch_scheduler_await_suspend(scheduler_t* sch);
LIBRF_API bool switch_scheduler_await_suspend(scheduler_t* sch);

template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>>
void promise_initial_suspend(coroutine_handle<_PromiseT> handler);
@@ -312,12 +312,12 @@ namespace librf
private:
explicit state_t(bool awaitor) noexcept :state_future_t(awaitor) {}
public:
void future_await_resume();
LIBRF_API void future_await_resume();
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>>
void promise_yield_value(_PromiseT* promise);

void set_exception(std::exception_ptr e);
void set_value();
LIBRF_API void set_exception(std::exception_ptr e);
LIBRF_API void set_value();

template<class _Exp>
inline void throw_exception(_Exp e)

+ 7
- 7
include/librf/src/timer.h View File

@@ -94,8 +94,8 @@ namespace librf
typedef std::multimap<clock_type::time_point, timer_target_ptr> timer_map_type;
#endif
public:
timer_manager();
~timer_manager();
LIBRF_API timer_manager();
LIBRF_API ~timer_manager();

template<class _Rep, class _Period, class _Cb>
timer_target_ptr add(const std::chrono::duration<_Rep, _Period> & dt_, _Cb && cb_)
@@ -118,14 +118,14 @@ namespace librf
return{ this, add(tp_, std::forward<_Cb>(cb_)) };
}

bool stop(const timer_target_ptr & sptr);
LIBRF_API bool stop(const timer_target_ptr & sptr);

inline bool empty() const
{
return _runing_timers.empty() && _added_timers.empty();
}
void clear();
void update();
LIBRF_API void clear();
LIBRF_API void update();

#ifndef DOXYGEN_SKIP_PROPERTY
template<class _Cb>
@@ -145,8 +145,8 @@ namespace librf
timer_vector_type _added_timers;
timer_map_type _runing_timers;

timer_target_ptr add_(const timer_target_ptr & sptr);
static void call_target_(const timer_target_ptr & sptr, bool canceld);
LIBRF_API timer_target_ptr add_(const timer_target_ptr & sptr);
LIBRF_API static void call_target_(const timer_target_ptr & sptr, bool canceld);
#endif
};


+ 6
- 6
include/librf/src/when_v2.h View File

@@ -22,14 +22,14 @@ namespace librf
{
struct state_when_t : public state_base_t
{
state_when_t(intptr_t counter_);
LIBRF_API state_when_t(intptr_t counter_);

virtual void resume() override;
virtual bool has_handler() const noexcept override;
LIBRF_API virtual void resume() override;
LIBRF_API virtual bool has_handler() const noexcept override;

void on_cancel() noexcept;
bool on_notify_one();
bool on_timeout();
LIBRF_API void on_cancel() noexcept;
LIBRF_API bool on_notify_one();
LIBRF_API bool on_timeout();

//将自己加入到通知链表里
template<class _PromiseT, typename = std::enable_if_t<traits::is_promise_v<_PromiseT>>>

+ 15
- 15
source/event_v2.cpp View File

@@ -4,7 +4,7 @@ namespace librf
{
namespace detail
{
void state_event_base_t::resume()
LIBRF_API void state_event_base_t::resume()
{
coroutine_handle<> handler = _coro;
if (handler)
@@ -15,12 +15,12 @@ namespace librf
}
}

bool state_event_base_t::has_handler() const noexcept
LIBRF_API bool state_event_base_t::has_handler() const noexcept
{
return (bool)_coro;
}

void state_event_t::on_cancel() noexcept
LIBRF_API void state_event_t::on_cancel() noexcept
{
event_v2_impl** oldValue = _value.load(std::memory_order_acquire);
if (oldValue != nullptr && _value.compare_exchange_strong(oldValue, nullptr, std::memory_order_acq_rel))
@@ -32,7 +32,7 @@ namespace librf
}
}

bool state_event_t::on_notify(event_v2_impl* eptr)
LIBRF_API bool state_event_t::on_notify(event_v2_impl* eptr)
{
event_v2_impl** oldValue = _value.load(std::memory_order_acquire);
if (oldValue != nullptr && _value.compare_exchange_strong(oldValue, nullptr, std::memory_order_acq_rel))
@@ -49,7 +49,7 @@ namespace librf
return false;
}

bool state_event_t::on_timeout()
LIBRF_API bool state_event_t::on_timeout()
{
event_v2_impl** oldValue = _value.load(std::memory_order_acquire);
if (oldValue != nullptr && _value.compare_exchange_strong(oldValue, nullptr, std::memory_order_acq_rel))
@@ -69,7 +69,7 @@ namespace librf



void state_event_all_t::on_cancel() noexcept
LIBRF_API void state_event_all_t::on_cancel() noexcept
{
intptr_t oldValue = _counter.load(std::memory_order_acquire);
if (oldValue >= 0 && _counter.compare_exchange_strong(oldValue, -1, std::memory_order_acq_rel))
@@ -81,7 +81,7 @@ namespace librf
}
}

bool state_event_all_t::on_notify(event_v2_impl*)
LIBRF_API bool state_event_all_t::on_notify(event_v2_impl*)
{
intptr_t oldValue = _counter.load(std::memory_order_acquire);
if (oldValue <= 0) return false;
@@ -102,7 +102,7 @@ namespace librf
return oldValue >= 1;
}

bool state_event_all_t::on_timeout()
LIBRF_API bool state_event_all_t::on_timeout()
{
intptr_t oldValue = _counter.load(std::memory_order_acquire);
if (oldValue >= 0 && _counter.compare_exchange_strong(oldValue, -1, std::memory_order_acq_rel))
@@ -121,7 +121,7 @@ namespace librf



event_v2_impl::event_v2_impl(bool initially) noexcept
LIBRF_API event_v2_impl::event_v2_impl(bool initially) noexcept
: _counter(initially ? 1 : 0)
{
}
@@ -153,12 +153,12 @@ namespace librf
list.clear();
}

event_v2_impl::~event_v2_impl()
LIBRF_API event_v2_impl::~event_v2_impl()
{
clear_list(_wait_awakes);
}

void event_v2_impl::signal_all() noexcept
LIBRF_API void event_v2_impl::signal_all() noexcept
{
scoped_lock<lock_type> lock_(_lock);

@@ -171,7 +171,7 @@ namespace librf
}
}

void event_v2_impl::signal() noexcept
LIBRF_API void event_v2_impl::signal() noexcept
{
scoped_lock<lock_type> lock_(_lock);

@@ -186,16 +186,16 @@ namespace librf
}
}

event_t::event_t(bool initially)
LIBRF_API event_t::event_t(bool initially)
:_event(std::make_shared<detail::event_v2_impl>(initially))
{
}

event_t::event_t(std::adopt_lock_t)
LIBRF_API event_t::event_t(std::adopt_lock_t)
{
}

event_t::~event_t()
LIBRF_API event_t::~event_t()
{
}
}

+ 16
- 16
source/mutex_v2.cpp View File

@@ -4,7 +4,7 @@ namespace librf
{
namespace detail
{
void state_mutex_t::resume()
LIBRF_API void state_mutex_t::resume()
{
coroutine_handle<> handler = _coro;
if (handler)
@@ -15,18 +15,18 @@ namespace librf
}
}

bool state_mutex_t::has_handler() const noexcept
LIBRF_API bool state_mutex_t::has_handler() const noexcept
{
return (bool)_coro;
}
state_base_t* state_mutex_t::get_parent() const noexcept
LIBRF_API state_base_t* state_mutex_t::get_parent() const noexcept
{
return _root;
}


void state_mutex_t::on_cancel() noexcept
LIBRF_API void state_mutex_t::on_cancel() noexcept
{
mutex_v2_impl** oldValue = _value.load(std::memory_order_acquire);
if (oldValue != nullptr && _value.compare_exchange_strong(oldValue, nullptr, std::memory_order_acq_rel))
@@ -38,7 +38,7 @@ namespace librf
}
}

bool state_mutex_t::on_notify(mutex_v2_impl* eptr)
LIBRF_API bool state_mutex_t::on_notify(mutex_v2_impl* eptr)
{
assert(eptr != nullptr);

@@ -57,7 +57,7 @@ namespace librf
return false;
}

bool state_mutex_t::on_timeout()
LIBRF_API bool state_mutex_t::on_timeout()
{
mutex_v2_impl** oldValue = _value.load(std::memory_order_acquire);
if (oldValue != nullptr && _value.compare_exchange_strong(oldValue, nullptr, std::memory_order_acq_rel))
@@ -74,7 +74,7 @@ namespace librf
return false;
}

void state_mutex_t::add_timeout_timer(std::chrono::system_clock::time_point tp)
LIBRF_API void state_mutex_t::add_timeout_timer(std::chrono::system_clock::time_point tp)
{
this->_thandler = this->_scheduler->timer()->add_handler(tp,
[st = counted_ptr<state_mutex_t>{ this }](bool canceld)
@@ -86,7 +86,7 @@ namespace librf



void mutex_v2_impl::lock_until_succeed(void* sch)
LIBRF_API void mutex_v2_impl::lock_until_succeed(void* sch)
{
assert(sch != nullptr);

@@ -98,7 +98,7 @@ namespace librf
}
}

bool mutex_v2_impl::try_lock(void* sch)
LIBRF_API bool mutex_v2_impl::try_lock(void* sch)
{
assert(sch != nullptr);

@@ -106,7 +106,7 @@ namespace librf
return try_lock_lockless(sch);
}

bool mutex_v2_impl::try_lock_until(clock_type::time_point tp, void* sch)
LIBRF_API bool mutex_v2_impl::try_lock_until(clock_type::time_point tp, void* sch)
{
assert(sch != nullptr);

@@ -119,7 +119,7 @@ namespace librf
return false;
}

bool mutex_v2_impl::try_lock_lockless(void* sch) noexcept
LIBRF_API bool mutex_v2_impl::try_lock_lockless(void* sch) noexcept
{
assert(sch != nullptr);

@@ -138,7 +138,7 @@ namespace librf
return false;
}

bool mutex_v2_impl::unlock(void* sch)
LIBRF_API bool mutex_v2_impl::unlock(void* sch)
{
assert(sch != nullptr);

@@ -175,7 +175,7 @@ namespace librf
return false;
}

void mutex_v2_impl::add_wait_list_lockless(state_mutex_t* state)
LIBRF_API void mutex_v2_impl::add_wait_list_lockless(state_mutex_t* state)
{
assert(state != nullptr);

@@ -183,16 +183,16 @@ namespace librf
}
}

mutex_t::mutex_t()
LIBRF_API mutex_t::mutex_t()
: _mutex(std::make_shared<detail::mutex_v2_impl>())
{
}

mutex_t::mutex_t(std::adopt_lock_t) noexcept
LIBRF_API mutex_t::mutex_t(std::adopt_lock_t) noexcept
{
}

mutex_t::~mutex_t() noexcept
LIBRF_API mutex_t::~mutex_t() noexcept
{
}
}

+ 3
- 3
source/rf_task.cpp View File

@@ -2,16 +2,16 @@

namespace librf
{
task_t::task_t() noexcept
LIBRF_API task_t::task_t() noexcept
: _stop(nostopstate)
{
}

task_t::~task_t()
LIBRF_API task_t::~task_t()
{
}

const stop_source & task_t::get_stop_source()
LIBRF_API const stop_source & task_t::get_stop_source()
{
_stop.make_sure_possible();
return _stop;

+ 12
- 12
source/scheduler.cpp View File

@@ -24,7 +24,7 @@ namespace librf

char sz_future_error_buffer[256];

const char * get_error_string(error_code fe, const char * classname)
LIBRF_API const char * get_error_string(error_code fe, const char * classname)
{
if (classname)
{
@@ -40,12 +40,12 @@ namespace librf
thread_local scheduler_t * th_scheduler_ptr = nullptr;

//获得当前线程下的调度器
scheduler_t * this_scheduler()
LIBRF_API scheduler_t * this_scheduler()
{
return th_scheduler_ptr ? th_scheduler_ptr : &scheduler_t::g_scheduler;
}

local_scheduler_t::local_scheduler_t()
LIBRF_API local_scheduler_t::local_scheduler_t()
{
if (th_scheduler_ptr == nullptr)
{
@@ -58,7 +58,7 @@ namespace librf
}
}

local_scheduler_t::local_scheduler_t(scheduler_t& sch) noexcept
LIBRF_API local_scheduler_t::local_scheduler_t(scheduler_t& sch) noexcept
{
if (th_scheduler_ptr == nullptr)
{
@@ -68,14 +68,14 @@ namespace librf
_scheduler_ptr = nullptr;
}

local_scheduler_t::~local_scheduler_t()
LIBRF_API local_scheduler_t::~local_scheduler_t()
{
if (th_scheduler_ptr == _scheduler_ptr)
th_scheduler_ptr = nullptr;
delete _scheduler_ptr;
}

scheduler_t::scheduler_t()
LIBRF_API scheduler_t::scheduler_t()
: _timer(std::make_shared<timer_manager>())
{
_runing_states.reserve(1024);
@@ -85,14 +85,14 @@ namespace librf
th_scheduler_ptr = this;
}

scheduler_t::~scheduler_t()
LIBRF_API scheduler_t::~scheduler_t()
{
//cancel_all_task_();
if (th_scheduler_ptr == this)
th_scheduler_ptr = nullptr;
}

task_t* scheduler_t::new_task(task_t * task)
LIBRF_API task_t* scheduler_t::new_task(task_t * task)
{
state_base_t* sptr = task->_state.get();
sptr->set_scheduler(this);
@@ -113,7 +113,7 @@ namespace librf
return task;
}

std::unique_ptr<task_t> scheduler_t::del_switch(state_base_t* sptr)
LIBRF_API std::unique_ptr<task_t> scheduler_t::del_switch(state_base_t* sptr)
{
#if !RESUMEF_DISABLE_MULT_THREAD
scoped_lock<spinlock> __guard(_lock_ready);
@@ -147,7 +147,7 @@ namespace librf
}
*/

bool scheduler_t::run_one_batch()
LIBRF_API bool scheduler_t::run_one_batch()
{
this->_timer->update();

@@ -168,7 +168,7 @@ namespace librf
return true;
}

void scheduler_t::run_until_notask()
LIBRF_API void scheduler_t::run_until_notask()
{
for(;;)
{
@@ -189,5 +189,5 @@ namespace librf
};
}

scheduler_t scheduler_t::g_scheduler;
LIBRF_API scheduler_t scheduler_t::g_scheduler;
}

+ 1
- 1
source/sleep.cpp View File

@@ -2,7 +2,7 @@

namespace librf
{
future_t<> sleep_until_(std::chrono::system_clock::time_point tp_, scheduler_t& scheduler_)
LIBRF_API future_t<> sleep_until_(std::chrono::system_clock::time_point tp_, scheduler_t& scheduler_)
{
awaitable_t<> awaitable;


+ 16
- 16
source/state.cpp View File

@@ -2,21 +2,21 @@

namespace librf
{
state_base_t::~state_base_t()
LIBRF_API state_base_t::~state_base_t()
{
}
void state_base_t::destroy_deallocate()
LIBRF_API void state_base_t::destroy_deallocate()
{
delete this;
}
state_base_t* state_base_t::get_parent() const noexcept
LIBRF_API state_base_t* state_base_t::get_parent() const noexcept
{
return nullptr;
}

void state_future_t::destroy_deallocate()
LIBRF_API void state_future_t::destroy_deallocate()
{
size_t _Size = this->_alloc_size;
#if RESUMEF_DEBUG_COUNTER
@@ -28,7 +28,7 @@ namespace librf
return _Al.deallocate(reinterpret_cast<char*>(this), _Size);
}

state_generator_t* state_generator_t::_Alloc_state()
LIBRF_API state_generator_t* state_generator_t::_Alloc_state()
{
_Alloc_char _Al;
size_t _Size = _Align_size<state_generator_t>();
@@ -39,7 +39,7 @@ namespace librf
return new(_Ptr) state_generator_t();
}

void state_generator_t::destroy_deallocate()
LIBRF_API void state_generator_t::destroy_deallocate()
{
size_t _Size = _Align_size<state_generator_t>();
#if RESUMEF_INLINE_STATE
@@ -55,7 +55,7 @@ namespace librf
return _Al.deallocate(reinterpret_cast<char*>(this), _Size);
}

void state_generator_t::resume()
LIBRF_API void state_generator_t::resume()
{
if (likely(_coro))
{
@@ -75,12 +75,12 @@ namespace librf
}
}

bool state_generator_t::has_handler() const noexcept
LIBRF_API bool state_generator_t::has_handler() const noexcept
{
return (bool)_coro;
}
bool state_generator_t::switch_scheduler_await_suspend(scheduler_t* sch)
LIBRF_API bool state_generator_t::switch_scheduler_await_suspend(scheduler_t* sch)
{
assert(sch != nullptr);

@@ -102,12 +102,12 @@ namespace librf
return true;
}

state_base_t* state_future_t::get_parent() const noexcept
LIBRF_API state_base_t* state_future_t::get_parent() const noexcept
{
return _parent;
}

void state_future_t::resume()
LIBRF_API void state_future_t::resume()
{
std::unique_lock<lock_type> __guard(_mtx);

@@ -146,13 +146,13 @@ namespace librf
}
}

bool state_future_t::has_handler() const noexcept
LIBRF_API bool state_future_t::has_handler() const noexcept
{
scoped_lock<lock_type> __guard(this->_mtx);
return has_handler_skip_lock();
}

bool state_future_t::switch_scheduler_await_suspend(scheduler_t* sch)
LIBRF_API bool state_future_t::switch_scheduler_await_suspend(scheduler_t* sch)
{
assert(sch != nullptr);
scoped_lock<lock_type> __guard(this->_mtx);
@@ -178,7 +178,7 @@ namespace librf
return true;
}

void state_t<void>::future_await_resume()
LIBRF_API void state_t<void>::future_await_resume()
{
scoped_lock<lock_type> __guard(this->_mtx);

@@ -188,7 +188,7 @@ namespace librf
std::rethrow_exception(std::make_exception_ptr(future_exception{error_code::not_ready}));
}

void state_t<void>::set_value()
LIBRF_API void state_t<void>::set_value()
{
scoped_lock<lock_type> __guard(this->_mtx);
this->_has_value.store(result_type::Value, std::memory_order_release);
@@ -203,7 +203,7 @@ namespace librf
}
}

void state_t<void>::set_exception(std::exception_ptr e)
LIBRF_API void state_t<void>::set_exception(std::exception_ptr e)
{
scoped_lock<lock_type> __guard(this->_mtx);
this->_exception = std::move(e);

+ 7
- 7
source/timer.cpp View File

@@ -2,17 +2,17 @@

namespace librf
{
timer_manager::timer_manager()
LIBRF_API timer_manager::timer_manager()
{
_added_timers.reserve(128);
}

timer_manager::~timer_manager()
LIBRF_API timer_manager::~timer_manager()
{
clear();
}
void timer_manager::call_target_(const timer_target_ptr & sptr, bool canceld)
LIBRF_API void timer_manager::call_target_(const timer_target_ptr & sptr, bool canceld)
{
auto cb = std::move(sptr->cb);
sptr->st = timer_target::State::Invalid;
@@ -23,7 +23,7 @@ namespace librf
if(cb) cb(canceld);
}

void timer_manager::clear()
LIBRF_API void timer_manager::clear()
{
#if !RESUMEF_DISABLE_MULT_THREAD
std::unique_lock<spinlock> __lock(_added_mtx);
@@ -41,7 +41,7 @@ namespace librf
call_target_(kv.second, true);
}

detail::timer_target_ptr timer_manager::add_(const timer_target_ptr & sptr)
LIBRF_API detail::timer_target_ptr timer_manager::add_(const timer_target_ptr & sptr)
{
assert(sptr);
assert(sptr->st == timer_target::State::Invalid);
@@ -60,7 +60,7 @@ namespace librf
return sptr;
}

bool timer_manager::stop(const timer_target_ptr & sptr)
LIBRF_API bool timer_manager::stop(const timer_target_ptr & sptr)
{
if (!sptr || sptr->st == timer_target::State::Invalid)
return false;
@@ -72,7 +72,7 @@ namespace librf
return true;
}

void timer_manager::update()
LIBRF_API void timer_manager::update()
{
{
#if !RESUMEF_DISABLE_MULT_THREAD

+ 6
- 6
source/when_v2.cpp View File

@@ -4,12 +4,12 @@ namespace librf
{
namespace detail
{
state_when_t::state_when_t(intptr_t counter_)
LIBRF_API state_when_t::state_when_t(intptr_t counter_)
:_counter(counter_)
{
}

void state_when_t::resume()
LIBRF_API void state_when_t::resume()
{
coroutine_handle<> handler = _coro;
if (handler)
@@ -20,12 +20,12 @@ namespace librf
}
}

bool state_when_t::has_handler() const noexcept
LIBRF_API bool state_when_t::has_handler() const noexcept
{
return (bool)_coro;
}

void state_when_t::on_cancel() noexcept
LIBRF_API void state_when_t::on_cancel() noexcept
{
scoped_lock<lock_type> lock_(_lock);

@@ -33,7 +33,7 @@ namespace librf
this->_coro = nullptr;
}

bool state_when_t::on_notify_one()
LIBRF_API bool state_when_t::on_notify_one()
{
scoped_lock<lock_type> lock_(_lock);

@@ -48,7 +48,7 @@ namespace librf
return false;
}

bool state_when_t::on_timeout()
LIBRF_API bool state_when_t::on_timeout()
{
scoped_lock<lock_type> lock_(_lock);


Loading…
Cancel
Save