1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
| // Code compilé ici : http://coliru.stacked-crooked.com/
// Version de g++ : 6.1.0
// Commande : g++ -std=c++14 -O2 -Wall -pedantic -pthread -fpermissive main.cpp && ./a.out
#include <iostream>
#include <mutex>
#include <tuple>
#include <utility>
namespace jo_link_noir
{
template<typename Lockable>
std::unique_lock<Lockable>
try_to_lock(Lockable & lock)
{
return std::unique_lock<Lockable>(lock, std::try_to_lock);
}
template<std::size_t I, class LockableTuple>
std::size_t
try_lock_impl(std::integer_sequence<std::size_t, I>, LockableTuple const & t)
{
auto ulock = try_to_lock(std::get<I>(t));
if (ulock.owns_lock()) {
ulock.release();
return std::tuple_size<LockableTuple>::value;
}
return I;
}
template<std::size_t I, std::size_t... Ints, class LockableTuple>
std::size_t
try_lock_impl(std::integer_sequence<std::size_t, I, Ints...>, LockableTuple const & t)
{
auto ulock = try_to_lock(std::get<I>(t));
if (ulock.owns_lock()) {
auto id = try_lock_impl(std::integer_sequence<std::size_t, Ints...>{}, t);
if (id == std::tuple_size<LockableTuple>::value) {
ulock.release();
}
return id;
}
return I;
}
template<std::size_t First, std::size_t Int, std::size_t... Ints, class LockableTuple>
std::size_t
lock_impl_from(std::integer_sequence<std::size_t, Int, Ints...>, LockableTuple const & t)
{
auto & lock = u1(std::get<First>(t));
// /usr/local/include/c++/6.1.0/tuple: In instantiation of 'class std::tuple_element<1ul, std::tuple<std::mutex&> >':
// /usr/local/include/c++/6.1.0/tuple:1205:12: recursively required from 'class std::tuple_element<2ul, std::tuple<std::recursive_mutex&, std::mutex&> >'
// /usr/local/include/c++/6.1.0/tuple:1205:12: required from 'class std::tuple_element<3ul, std::tuple<std::mutex&, std::recursive_mutex&, std::mutex&> >'
// /usr/local/include/c++/6.1.0/utility:106:69: required by substitution of 'template<long unsigned int __i, class _Tp> using __tuple_element_t = typename std::tuple_element::type [with long unsigned int __i = 3ul; _Tp = std::tuple<std::mutex&, std::recursive_mutex&, std::mutex&>]'
// /usr/local/include/c++/6.1.0/tuple:1241:5: required by substitution of 'template<long unsigned int __i, class ... _Elements> constexpr std::__tuple_element_t<__i, std::tuple<_Elements ...> >& std::get(const std::tuple<_Elements ...>&) [with long unsigned int __i = 3ul; _Elements = {std::mutex&, std::recursive_mutex&, std::mutex&}]'
// main.cpp:52:35: required from 'std::size_t jo_link_noir::lock_impl_from(std::integer_sequence<long unsigned int, Int, Ints ...>, const LockableTuple&) [with long unsigned int First = 3ul; long unsigned int Int = 3ul; long unsigned int ...Ints = {}; LockableTuple = std::tuple<std::mutex&, std::recursive_mutex&, std::mutex&>; std::size_t = long unsigned int]'
// main.cpp:71:86: required from 'void jo_link_noir::lock_impl(std::integer_sequence<long unsigned int, _Idx ...>, const LockableTuple&) [with long unsigned int ...Ints = {3ul}; LockableTuple = std::tuple<std::mutex&, std::recursive_mutex&, std::mutex&>]'
// main.cpp:86:12: required from 'void jo_link_noir::lock(Lockable1&, Lockable2&, Lockables& ...) [with Lockable1 = std::mutex; Lockable2 = std::recursive_mutex; Lockables = {std::mutex}]'
// main.cpp:96:31: required from here
// /usr/local/include/c++/6.1.0/tuple:1205:12: error: invalid use of incomplete type 'class std::tuple_element<0ul, std::tuple<> >'
// struct tuple_element<__i, tuple<_Head, _Tail...> >
// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// In file included from /usr/local/include/c++/6.1.0/tuple:38:0,
// from /usr/local/include/c++/6.1.0/mutex:38,
// from main.cpp:7:
// /usr/local/include/c++/6.1.0/utility:102:12: note: declaration of 'class std::tuple_element<0ul, std::tuple<> >'
// struct tuple_element;
// ^~~~~~~~~~~~~
std::unique_lock<std::remove_reference_t<decltype(lock)>> ulock(lock);
auto id = try_lock_impl(std::integer_sequence<std::size_t, (Ints + First) % sizeof...(Ints) ...>{}, t);
if (id == std::tuple_size<LockableTuple>::value) {
ulock.release();
}
return id;
}
template<std::size_t... Ints, class LockableTuple>
void
lock_impl(std::integer_sequence<std::size_t, Ints...> ints, LockableTuple const & t)
{
std::size_t const lock_count = sizeof...(Ints);
std::size_t lock_first = 0;
for (;;) {
bool has_result = false; //////////////////// ajout de ";"
// une espèce de switch pas optimisé
(void)std::initializer_list<int>{(( //////////////////// ajout d'une 2e parenthèse
(not has_result && Ints == lock_first) ? void(lock_first = lock_impl_from<Ints>(ints, t), has_result = 1) : void()
), 1)...}; //////////////////// déplacement du "..."
// main.cpp:71:48: warning: expression list treated as compound expression in functional cast [-fpermissive]
// (not has_result && Ints == lock_first) ? void(lock_first = lock_impl_from<Ints>(ints, t), has_result = 1) : void()
// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (lock_first == sizeof...(Ints)) {
return;
}
}
}
template<class Lockable1, class Lockable2, class... Lockables>
void
lock(Lockable1 & lock1, Lockable2 & lock2, Lockables &... locks)
{
lock_impl(std::index_sequence<sizeof...(Lockables)+2>{}, std::forward_as_tuple(lock1, lock2, locks...));
}
} // namespace jo_link_noir
int main()
{
std::cout << "Version de g++ : " << __VERSION__ << "\n\n";
std::mutex m1, m3;
std::recursive_mutex m2;
jo_link_noir::lock(m1, m2, m3);
m1.unlock();
m2.unlock();
m3.unlock();
return 0;
} |
Partager