Commit 4cb07bf6 authored by Damien Leroux's avatar Damien Leroux
Browse files

Fixed some race conditions. Fixed bug when using locus not in test positions...

Fixed some race conditions. Fixed bug when using locus not in test positions by snapping the locus to the test positions.
parent ec86fce1
......@@ -23,10 +23,22 @@ project(spell_qtl)
find_package(Boost 1.56.0 REQUIRED)
#set(CMAKE_CONFIGURATION_TYPES Debug Release CACHE INTERNAL FORCE)
FIND_PACKAGE(PythonInterp 3)
FIND_PACKAGE(PythonLibs 3)
if (${PYTHON_VERSION_MAJOR} EQUAL 3)
FIND_PACKAGE(Boost COMPONENTS python3)
SET(Boost_PYTHON_LIBRARY boost_python-py35)
else()
FIND_PACKAGE(Boost COMPONENTS python)
endif()
include_directories(AFTER ${PYTHON_INCLUDE_DIR})
set(CMAKE_VERBOSE_MAKEFILE ON)
set(BUILD_FOR_DEPLOYMENT FALSE CACHE BOOL "Link against static libc++ and use minimal symbol version where possible")
set(SANITIZER "" CACHE STRING "Select sanitizer (see compiler manpage for available options)")
MESSAGE(STATUS "CMAKE VERSION ${CMAKE_VERSION}")
MESSAGE(STATUS "${CMAKE_CURRENT_SOURCE_DIR}")
......@@ -52,11 +64,11 @@ MESSAGE(STATUS "VERSION ${VERSION}")
LIST(GET VERSION 0 VERSION_MAJOR)
LIST(GET VERSION 1 VERSION_MINOR)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 14)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wextra -Wall -Wno-unused-parameter -pthread -fPIC")
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O2 -DNDEBUG -DEIGEN_NO_DEBUG")
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -O0 -ggdb")
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -Og -ggdb")
add_definitions(-DEIGEN_NO_DEPRECATED_WARNING -DVERSION_MAJOR=\"${VERSION_MAJOR}\" -DVERSION_MINOR=\"${VERSION_MINOR}\" -DVERSION_PATCH=\"${VERSION_PATCH}\")
......@@ -111,7 +123,13 @@ MESSAGE(STATUS "spell-pedigree src = ${SPELL_PEDIGREE_SRC}")
# message(STATUS "${_variableName}=${${_variableName}}")
#endforeach()
if(${BUILD_FOR_DEPLOYMENT})
if ("${SANITIZER}" STREQUAL "")
set(SANITIZER_OPT "")
else()
set(SANITIZER_OPT "-fsanitize=${SANITIZER}")
endif()
if (${BUILD_FOR_DEPLOYMENT})
add_executable(spell-pedigree ${SPELL_PEDIGREE_SRC} ${libstdcpp})
add_executable(spell-marker ${SPELL_MARKER_SRC})
add_executable(spell-qtl ${SPELL_QTL_SRC} ${libstdcpp})
......@@ -131,7 +149,7 @@ if(${BUILD_FOR_DEPLOYMENT})
SET_SOURCE_FILES_PROPERTIES(${SPELL_PEDIGREE_SRC} ${SPELL_MARKER_SRC} ${SPELL_QTL_SRC}
PROPERTIES
OBJECT_DEPENDS glibc.h
COMPILE_FLAGS "-include ${CMAKE_BINARY_DIR}/glibc.h -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0")
COMPILE_FLAGS "-include ${CMAKE_BINARY_DIR}/glibc.h -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 ${SANITIZER_OPT}")
#add_dependencies(stdc++ libstdc++.a)
#add_dependencies(gmp libgmp.a)
......@@ -152,13 +170,13 @@ else()
add_executable(spell-qtl ${SPELL_QTL_SRC})
SET_SOURCE_FILES_PROPERTIES(${SPELL_PEDIGREE_SRC} ${SPELL_MARKER_SRC} ${SPELL_QTL_SRC}
PROPERTIES
COMPILE_FLAGS "-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0")
COMPILE_FLAGS "-Wno-int-in-bool-context -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 ${SANITIZER_OPT}")
target_compile_definitions(spell-qtl PUBLIC SPELL_USE_XLNT)
set(CMAKE_EXE_LINKER_FLAGS "-rdynamic")
set(CMAKE_EXE_LINKER_FLAGS "-rdynamic ${SANITIZER_OPT}")
endif()
target_link_libraries(spell-marker dl gmp)
target_link_libraries(spell-qtl xlnt dl rt)
target_link_libraries(spell-qtl ${Boost_PYTHON_LIBRARY} ${PYTHON_LIBRARY} xlnt dl rt)
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
......
......@@ -70,13 +70,20 @@ register_task_in_progress(std::shared_ptr<async_computation<Ret(Args...)>> v,
Ret (*f) (Args...),
const value<typename clean_type<Args>::type>&... args)
{
/*__get_in_progress_mutex<Ret, Args...>().lock();*/
// __get_in_progress_mutex<Ret, Args...>().lock();
__get_in_progress_registry<Ret, Args...>().get(f, args...) = v;
/*__get_in_progress_mutex<Ret, Args...>().unlock();*/
// __get_in_progress_mutex<Ret, Args...>().unlock();
return v;
}
template <typename Ret, typename... Args>
struct lock_in_progress_mutex {
lock_in_progress_mutex() { __get_in_progress_mutex<Ret, Args...>().lock(); }
~lock_in_progress_mutex() { __get_in_progress_mutex<Ret, Args...>().unlock(); }
};
template <typename Ret, typename... Args>
struct async_computation<Ret(Args...)> : public Task {
typedef async_computation<Ret(Args...)> this_type;
......@@ -96,6 +103,11 @@ template <typename Ret, typename... Args>
, m_storage()
, m_future()
, m_compute([=] () {
{
std::unique_lock<std::mutex> lock(mutex);
m_started = true;
m_started_cv.notify_all();
}
/*
bool previous = m_started.exchange(true);
if (previous) {
......@@ -132,7 +144,9 @@ template <typename Ret, typename... Args>
TaskPool::release_slot();
// TaskPool::remove_task(m_thread->get_id());
// MSG_DEBUG("[" << this_id << ',' << (this_id == active_settings->main_thread) << "] LEAVE " << func_name);
m_started_cv.notify_all();
// mutex.lock();
// m_started_cv.notify_all();
// mutex.unlock();
return ret;
})
, mutex()
......@@ -142,7 +156,7 @@ template <typename Ret, typename... Args>
, m_storage_waiting_cv()
{
// MSG_DEBUG("In constructor, thread " << (&m_thread) << " should not be joinable: " << std::boolalpha << m_thread.joinable());
std::unique_lock<std::mutex> lock(mutex);
// std::unique_lock<std::mutex> lock(mutex);
// if (!m_started) {
// m_started.store(true);
TaskPool::enqueue(this);
......@@ -160,7 +174,16 @@ template <typename Ret, typename... Args>
// , m_promise()
, m_future()
, m_compute([=] () {
{
std::unique_lock<std::mutex> lock(mutex);
m_started = true;
m_started_cv.notify_all();
}
// {
// std::unique_lock<std::mutex> lock(mutex);
// m_started_cv.notify_all();
// }
/*
bool previous = m_started.exchange(true);
if (previous) {
......@@ -191,14 +214,20 @@ template <typename Ret, typename... Args>
// msg_handler_t::run_hooks();
// m_promise.set_value(proxy(*args...));
*/
// mutex.lock();
auto ret = proxy(*args...);
// mutex.unlock();
// MSG_DEBUG("[" << this_id << ',' << (this_id == active_settings->main_thread) << "] p LEAVE " << func_name);
// active_settings->thread_stacks[this_id].pop_back();
// msg_handler_t::run_hooks();
unregister_task_in_progress(func, {*args}...);
TaskPool::release_slot();
// TaskPool::remove_task(m_thread->get_id());
m_started_cv.notify_all();
// mutex.lock();
// m_started_cv.notify_all();
// mutex.unlock();
return ret;
})
/*, m_future(std::async(func, *args...))*/
......@@ -209,7 +238,7 @@ template <typename Ret, typename... Args>
, m_storage_waiting_cv()
{
// MSG_DEBUG("In constructor (w/ proxy), thread " << (&m_thread) << " should not be joinable: " << std::boolalpha << m_thread.joinable());
std::unique_lock<std::mutex> lock(mutex);
// std::unique_lock<std::mutex> lock(mutex);
// if (!m_started) {
// m_started.store(true);
TaskPool::enqueue(this);
......@@ -220,18 +249,16 @@ template <typename Ret, typename... Args>
std::thread::id run() override
{
std::unique_lock<std::mutex> lock(mutex);
if (m_started) {
MSG_ERROR("Task has already run.", "");
return {};
} else {
std::unique_lock<std::mutex> lock(mutex);
m_future = std::async(std::launch::async, m_compute);
// m_thread.reset(new std::thread(std::move(m_compute)));
// m_thread = new std::thread(std::move(m_compute));
// m_thread.detach();
// return m_thread->get_id();
m_started = true;
m_started_cv.notify_all();
return {};
}
}
......@@ -248,24 +275,33 @@ template <typename Ret, typename... Args>
if (m_storage_init) {
return m_storage;
}
TaskPool::wait([this]() {
// TaskPool::wait([&lock, this]() {
// mutex.lock();
TaskPool::release_slot();
{
if (!m_started.load()) {
std::unique_lock<std::mutex> lock(mutex);
if (!m_started) {
m_started_cv.wait(lock, [this]() -> bool { return m_started; });
}
if (!m_storage_init && m_future.valid()) {
bool waiting_for_storage = m_storage_waiting.exchange(true);
if (waiting_for_storage) {
m_storage_waiting_cv.wait(lock, [this] () -> bool { return m_storage_init; });
} else {
m_storage = m_future.get();
m_storage_init.store(true);
m_storage_waiting_cv.notify_all();
}
m_started_cv.wait(lock, [this]() { return m_started.load(); });
}
// if (!m_storage_init && m_future.valid()) {
bool waiting_for_storage = m_storage_waiting.exchange(true);
if (waiting_for_storage) {
std::unique_lock<std::mutex> lock(mutex);
m_storage_waiting_cv.wait(lock, [this] () -> bool { return m_storage_init; });
} else {
// mutex.unlock();
m_storage = m_future.get();
std::unique_lock<std::mutex> lock(mutex);
// mutex.lock();
m_storage_init.store(true);
m_storage_waiting_cv.notify_all();
// mutex.unlock();
}
// }
}
TaskPool::take_slot();
// mutex.unlock();
});
// });
// mutex.lock();
// }
// mutex.unlock();
......@@ -279,16 +315,16 @@ template <typename Ret, typename... Args>
protected:
std::tuple<value<typename clean_type<Args>::type>...> dependencies;
std::atomic_bool m_storage_init;
mutable std::atomic_bool m_storage_init;
// std::unique_ptr<std::thread> m_thread;
value_type m_storage;
std::future<Ret> m_future;
mutable value_type m_storage;
mutable std::future<Ret> m_future;
std::function<Ret()> m_compute;
std::mutex mutex;
std::atomic_bool m_started;
std::condition_variable m_started_cv;
std::atomic_bool m_storage_waiting;
std::condition_variable m_storage_waiting_cv;
mutable std::mutex mutex;
mutable std::atomic_bool m_started;
mutable std::condition_variable m_started_cv;
mutable std::atomic_bool m_storage_waiting;
mutable std::condition_variable m_storage_waiting_cv;
};
template <typename Ret, typename... Args>
......@@ -301,7 +337,7 @@ std::shared_ptr<async_computation<Ret(Args...)>>
/*_mac_guard() { __get_in_progress_mutex<Ret, Args...>().lock(); }*/
/*~_mac_guard() { __get_in_progress_mutex<Ret, Args...>().unlock(); }*/
/*} _;*/
std::lock_guard<std::mutex> scope_lock(__get_in_progress_mutex<Ret, Args...>());
// std::lock_guard<std::mutex> scope_lock(__get_in_progress_mutex<Ret, Args...>());
auto& r = __get_in_progress_registry<Ret, Args...>();
auto exists = r.find(func, args...);
if (exists) {
......@@ -309,6 +345,7 @@ std::shared_ptr<async_computation<Ret(Args...)>>
} else {
std::shared_ptr<async_computation<Ret(Args...)>>
ac(new async_computation<Ret(Args...)>(_Sync, func, args...));
lock_in_progress_mutex<Ret, Args...> _;
return r.get(func, args...) = register_task_in_progress(ac, func, args...);
}
}
......@@ -325,14 +362,17 @@ std::shared_ptr<async_computation<Ret(Args...)>>
/*_mac_guard() { __get_in_progress_mutex<Ret, Args...>().lock(); }*/
/*~_mac_guard() { __get_in_progress_mutex<Ret, Args...>().unlock(); }*/
/*} _;*/
std::lock_guard<std::mutex> scope_lock(__get_in_progress_mutex<Ret, Args...>());
// std::lock_guard<std::mutex> scope_lock(__get_in_progress_mutex<Ret, Args...>());
__get_in_progress_mutex<Ret, Args...>().lock();
auto& r = __get_in_progress_registry<Ret, Args...>();
auto exists = r.find(func, args...);
__get_in_progress_mutex<Ret, Args...>().unlock();
if (exists) {
return *exists;
} else {
std::shared_ptr<async_computation<Ret(Args...)>>
ac(new async_computation<Ret(Args...)>(_Sync, proxy, func, args...));
lock_in_progress_mutex<Ret, Args...> _;
return r.get(func, args...) = register_task_in_progress(ac, func, args...);
}
}
......
......@@ -55,9 +55,17 @@ template <typename RS, typename RF, typename CS, typename CF, typename M>
manipulator
matrix_with_sections(std::string title, const model_print::matrix_with_sections<RS, RF, CS, CF, M>& mws, std::function<void(int, int, xlnt::cell)> formatter = [] (int, int, xlnt::cell) {})
{
static auto set_mat_title = excel::merge(2, 2) << excel::align([] (xlnt::alignment& al) {
static auto set_mat_title = excel::merge(2, 2) << /*excel::align([] (xlnt::alignment& al) {
al.horizontal(xlnt::horizontal_alignment::center).vertical(xlnt::vertical_alignment::center);
})
}) << */ excel::cell_format([] (xlnt::format& fmt) {
xlnt::alignment al;
al.horizontal(xlnt::horizontal_alignment::center).vertical(xlnt::vertical_alignment::center);
fmt.alignment(al);
xlnt::font font;
font.bold(true).italic(true);
fmt.font(font);
})
<< excel::border_right(xlnt::color::black(), xlnt::border_style::thin)
<< excel::border_bottom(xlnt::color::black(), xlnt::border_style::thin)
;
......@@ -78,26 +86,6 @@ matrix_with_sections(std::string title, const model_print::matrix_with_sections<
xlnt::cell_reference origin = s.origin;
excel::push(s);
#if 0
s << excel::move(20, 2) << BT << BR << BL << BB;
s << excel::move(23, 2) << BT << BR << BB << BL;
s << excel::move(26, 2) << BT << BB << BR << BL;
s << excel::move(29, 2) << BB << BT << BR << BL;
s << excel::move(32, 2) << BT << BL << BB << BR;
s << excel::move(20, 5) << BT << BR << BL << BB;
s << excel::move(22, 5) << BT << BR << BB << BL;
s << excel::move(24, 5) << BT << BB << BR << BL;
s << excel::move(26, 5) << BB << BT << BR << BL;
s << excel::move(28, 5) << BT << BL << BB << BR;
s << excel::move(28, 8) << BT << BL << BB << BR;
s << excel::move(26, 8) << BB << BT << BR << BL;
s << excel::move(24, 8) << BT << BB << BR << BL;
s << excel::move(22, 8) << BT << BR << BB << BL;
s << excel::move(20, 8) << BT << BR << BL << BB;
#endif
// s << "ORIGIN";
/* column section labels */
s << excel::move(origin.make_offset(2, 0));
......@@ -145,7 +133,7 @@ matrix_with_sections(std::string title, const model_print::matrix_with_sections<
int r, c;
for (r = r0; r < r1 - 1; ++r) {
for (c = c0; c < c1 - 1; ++c) {
MSG_DEBUG('(' << r << ", " << c << ')');
// MSG_DEBUG('(' << r << ", " << c << ')');
s << mat(r, c);
formatter(r, c, s.sheet[s.cursor]);
s << excel::next_col;
......@@ -185,19 +173,34 @@ matrix_with_sections(std::string title, const model_print::matrix_with_sections<
};
}
inline
stream&
autosize(stream& s) {
auto dimensions = s.sheet.calculate_dimension();
for (xlnt::column_t::index_t c = dimensions.top_left().column_index(); c <= dimensions.top_right().column_index(); ++c) {
MSG_DEBUG("Computed width " << s.sheet.column_width(c));
}
for (xlnt::row_t r = dimensions.top_left().row(); r <= dimensions.bottom_left().row(); ++r) {
MSG_DEBUG("Computed height " << s.sheet.row_height(r));
}
return s;
template <typename A, int R, int C>
manipulator
matrix(const Eigen::Matrix<A, R, C>& mat)
{
return [&] (stream& s) {
for (int r = 0; r < mat.rows(); ++r) {
for (int c = 0; c < mat.cols(); ++c) {
s << mat(r, c) << excel::next_col;
}
s << excel::next_row;
}
return s;
};
}
// inline
// stream&
// autosize(stream& s) {
// auto dimensions = s.sheet.calculate_dimension();
// for (xlnt::column_t::index_t c = dimensions.top_left().column_index(); c <= dimensions.top_right().column_index(); ++c) {
// MSG_DEBUG("Computed width " << s.sheet.column_width(c));
// }
// for (xlnt::row_t r = dimensions.top_left().row(); r <= dimensions.bottom_left().row(); ++r) {
// MSG_DEBUG("Computed height " << s.sheet.row_height(r));
// }
// return s;
// }
} /* namespace excel */
#endif
......@@ -265,6 +265,7 @@ inline bool operator < (const forbidden_interval_type& fi1, const forbidden_inte
struct search_interval_type;
struct search_lg_type;
struct test_result {
search_lg_type* this_interval;
const chromosome* chrom;
......@@ -447,6 +448,33 @@ struct search_lg_type {
}
size_t
get_closest_index(double locus)
{
size_t i = 0;
size_t end = all_positions.size() - 1;
MSG_DEBUG("get_closest_index(" << locus << ") all_positions.size=" << all_positions.size());
MSG_DEBUG("position #" << i << " at " << all_positions[i]);
for (; i < end && all_positions[i] < locus; ++i) MSG_DEBUG("position #" << i << " at " << all_positions[i]);
if (i == 0 && i == end) {
return i;
}
double l = locus - all_positions[i - 1];
double r = all_positions[i] - locus;
return i - (l < r);
}
double
match_locus(double locus)
{
size_t i = get_closest_index(locus);
double new_locus = all_positions[i];
if (new_locus != locus) {
MSG_WARNING("Locus " << chrom->name << ':' << locus << " adjusted to test position " << new_locus);
}
return new_locus;
}
void
recompute_modes(double force_pos=-1)
{
......@@ -456,6 +484,9 @@ struct search_lg_type {
local_selections.resize(all_positions.size());
active_loci.clear();
active_loci.reserve(all_positions.size());
if (force_pos != -1) {
force_pos = match_locus(force_pos);
}
for (size_t i = 0; i < all_positions.size(); ++i) {
double locus = all_positions[i];
if (!!selection) {
......@@ -497,6 +528,7 @@ struct search_lg_type {
std::pair<value<model_block_type>, value<model_block_type>>
compute_at(const collection<population_value>& all_pops, double position)
{
position = match_locus(position);
recompute_modes(position);
compute_blocks(all_pops);
auto it = std::find(active_loci.begin(), active_loci.end(), position);
......@@ -514,9 +546,9 @@ struct search_lg_type {
auto ct = *vct;
auto last_computation =
(ct == ComputationType::FTest ? cac.ftest_pvalue
:ct == ComputationType::FTestLOD ? cac.ftest_lod
:ct == ComputationType::Chi2 ? cac.chi2
:/* has to be Chi2LOD */ cac.chi2_lod).middleCols(i0, active_loci.size());
: ct == ComputationType::FTestLOD ? cac.ftest_lod
: ct == ComputationType::Chi2 ? cac.chi2
:/* has to be Chi2LOD */ cac.chi2_lod).middleCols(i0, active_loci.size());
if (active_loci.size() != (size_t)(last_computation.outerSize())) {
MSG_ERROR("LOCI INCONSISTENT WITH COMPUTATION RESULT (" << active_loci.size() << " vs " << last_computation.outerSize() << ")", "");
abort();
......@@ -572,6 +604,7 @@ struct search_lg_type {
void
deselect(double position, const collection<population_value>& all_pops, value<model> M)
{
position = match_locus(position);
auto i = M->m_blocks.begin(), j = M->m_blocks.end();
std::vector<decltype(M->m_blocks.begin())> to_remove;
for (; i != j; ++i) {
......@@ -598,6 +631,7 @@ struct search_lg_type {
std::pair<model_block_key, model_block_key>
select(double pos)
{
pos = match_locus(pos);
MSG_DEBUG("select position " << pos);
size_t i_select = std::find(all_positions.begin(), all_positions.end(), pos) - all_positions.begin();
std::pair<model_block_key, model_block_key> ret;
......@@ -618,6 +652,7 @@ struct search_lg_type {
std::pair<model_block_key, model_block_key>
deselect(double pos)
{
pos = match_locus(pos);
MSG_DEBUG("deselect position " << pos);
size_t i_select = std::find(all_positions.begin(), all_positions.end(), pos) - all_positions.begin();
std::pair<model_block_key, model_block_key> ret;
......@@ -638,6 +673,7 @@ struct search_lg_type {
void
reduce(const collection<population_value>& all_pops, double position, value<model_block_type>& vblock)
{
position = match_locus(position);
/* FIXME what about dominance?? */
locus_key lk2 = selection - position;
auto pop_it = all_pops.begin();
......@@ -1028,7 +1064,6 @@ struct model_manager {
// auto i0i = i0_vec.begin();
// for (auto& si: chr_intervals.second) {
si.test(all_pops, 0, cac[chrom], vct, vcr, y_block_cols, vMcurrent, Mbase, threshold);
testpos[chrom].insert(testpos[chrom].end(), si.active_loci.begin(), si.active_loci.end());
if (last_best[chrom] < si.local_max) {
......@@ -1058,7 +1093,6 @@ struct model_manager {
last_computation[chrom] = NULL;
};
/*if (reporter) { reporter->report_computation(*vMcurrent, chr_intervals.first, cac[chrom], ct, cr, testpos[chrom]); }*/
report_computation(trait_name, chrom, si.active_loci, cac[chrom], si.local_max);
}
return cac;
......@@ -1158,7 +1192,7 @@ struct model_manager {
ret.emplace_back(chr->name, loc, sub.last_test_positions[chr], *sub.last_computation[chr]);
}
}
MSG_INFO("Keys after " << vMcurrent->keys());
// MSG_INFO("Keys after " << vMcurrent->keys());
return ret;
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -26,6 +26,161 @@
#include <sys/types.h>
#include <dirent.h>
#include <shared_mutex>
/*
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html#shared_mutex_imp
*/
#if 0
class shared_mutex
{
std::mutex mut_;
std::condition_variable gate1_;
std::condition_variable gate2_;
unsigned state_;
static const unsigned write_entered_ = 1U << (sizeof(unsigned)*CHAR_BIT - 1);
static const unsigned n_readers_ = ~write_entered_;
public:
shared_mutex() : state_(0) {}
// Exclusive ownership
inline void lock();
inline bool try_lock();
// bool timed_lock(nanoseconds rel_time);
inline void unlock();
// Shared ownership
inline void lock_shared();
inline bool try_lock_shared();
// bool timed_lock_shared(nanoseconds rel_time);
inline void unlock_shared();
};
// Exclusive ownership
void
shared_mutex::lock()
{
// std::this_thread::disable_interruption _;
std::unique_lock<std::mutex> lk(mut_);
while (state_ & write_entered_)
gate1_.wait(lk);
state_ |= write_entered_;
while (state_ & n_readers_)
gate2_.wait(lk);
}
bool
shared_mutex::try_lock()
{
std::unique_lock<std::mutex> lk(mut_, std::try_to_lock);
if (lk.owns_lock() && state_ == 0)
{
state_ = write_entered_;
return true;
}
return false;
}
void
shared_mutex::unlock()
{
// {
std::unique_lock<std::mutex> _(mut_);
state_ = 0;
// }
gate1_.notify_all();
}
// Shared ownership
void
shared_mutex::lock_shared()
{
// std::this_thread::disable_interruption _;
std::unique_lock<std::mutex> lk(mut_);
while ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_)