meganz/mingw-std-threads

Mutex, timed_mutex, and call_once are not fully standard-compliant

Closed this issue · 2 comments

Certain parts of the existing classes are not fully standard compliant. This comment lists them, lest we forget.

  • Classes mutex and timed_mutex do not satisfy the StandardLayoutType concept. (Will be fixed by #36)
    • Adding the variable mOwnerThread violates the requirement for the inheritance tree to have only one class that defines non-static members.
    • Compliance is practical, but possibly undesired.
      • Recursively locking a non-recursive mutex is undefined behavior.
      • Compliance would either remove error-checking code or bloat the recursive mutex classes.
  • Class mutex must have a constexpr constructor, but will not if both NDEBUG and STDMUTEX_NO_RECURSION_CHECKS are defined. (Will be fixed by #36)
    • Causes a compiler error to be thrown by once_flag.
      • If necessary, once_flag and call_once can be rewritten to use only an atomic_char and its compare_exchange_weak function, rather than depending on the mutex implementation. Efficiency of this implementation could be improved in Windows 8 by using WaitOnAddress. See #36
    • Compliance is impractical for Windows XP and Windows Vista.
      • Static initialization is not supported for CRITICAL_SECTION objects.
    • Compliance is possible for Windows 7.
  • Function call_once, and the thread constructor, do not behave as if calling invoke. In particular, member function pointers are not handled correctly. Member data members are less of a concern in this context, but still must be handled for standard compliance.
    • Compliance is possible.
      • If compiling for C++17, simply use invoke.
      • If compiling for C++11, use a helper class and template specialization to define an equivalent of invoke early.

According to cppreference.com, std::invoke is C++17, and std::call_once is C++11. If this is correct, the C++11 standard cannot require the implementation to use std::invoke

The cppreference.com site is somewhat inconsistent there. The call_once documentation indicates that invoke ought to be used before C++17, despite invoke being a C++17 feature. I think the intent is "call as if by invoke", which is still not quite satisfied by the current implementation.

I will adjust the issue accordingly.