class test
{
std::mutex m1;
public:
inline static int i{0};
void operator()()
{
m1.lock();
++i;
m1.unlock();
}
};
int main()
{
test t;
std::thread t1{t}; // doesn't work
// std::thread t1{std::ref(t)}; // works
t1.join();
cout << test::i << endl;
}
Error:
In file included from test.cpp:19:
/Library/Developer/CommandLineTools/usr/include/c++/v1/thread:365:17: error: no matching constructor for initialization of
'_Gp' (aka 'tuple<unique_ptr<std::__1::__thread_struct>, test>')
new _Gp(std::move(__tsp),
^ ~~~~~~~~~~~~~~~~~
test.cpp:53:17: note: in instantiation of function template specialization 'std::__1::thread::thread<test &, void>' requested
here
std::thread t1{t}; // doesn't work
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/tuple:625:5: note: candidate template ignored: requirement
'__lazy_and<is_same<allocator_arg_t, unique_ptr<__thread_struct, default_delete<__thread_struct> > >,
__lazy_all<__dependent_type<is_default_constructible<unique_ptr<__thread_struct, default_delete<__thread_struct> > >,
true>, __dependent_type<is_default_constructible<test>, true> > >::value' was not satisfied [with _AllocArgT =
std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, _Alloc = test,
_Dummy = true]
tuple(_AllocArgT, _Alloc const& __a)
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/tuple:641:5: note: candidate template ignored: requirement
'_CheckArgsConstructor<true>::template __enable_implicit<const std::__1::unique_ptr<std::__1::__thread_struct,
std::__1::default_delete<std::__1::__thread_struct> > &, const test &>()' was not satisfied [with _Dummy = true]
tuple(const _Tp& ... __t) _NOEXCEPT_((__all<is_nothrow_copy_constructible<_Tp>::value...>::value))
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/tuple:659:14: note: candidate template ignored: requirement
'_CheckArgsConstructor<true>::template __enable_explicit<const std::__1::unique_ptr<std::__1::__thread_struct,
std::__1::default_delete<std::__1::__thread_struct> > &, const test &>()' was not satisfied [with _Dummy = true]
explicit tuple(const _Tp& ... __t) _NOEXCEPT_((__all<is_nothrow_copy_constructible<_Tp>::value...>::value))
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/tuple:723:9: note: candidate template ignored: requirement
'_CheckArgsConstructor<sizeof...(_Up) == sizeof...(_Tp) && !false>::template
__enable_implicit<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >,
test>() || _CheckArgsConstructor<_EnableImplicitReducedArityExtension && sizeof...(_Up) < sizeof...(_Tp) &&
!false>::template __enable_implicit<std::__1::unique_ptr<std::__1::__thread_struct,
std::__1::default_delete<std::__1::__thread_struct> >, test>()' was not satisfied [with _Up =
<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, test>,
_PackIsTuple = false]
tuple(_Up&&... __u)
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/tuple:756:9: note: candidate template ignored: requirement
'_CheckArgsConstructor<sizeof...(_Up) <= sizeof...(_Tp) && !_PackExpandsToThisTuple<unique_ptr<__thread_struct,
default_delete<__thread_struct> >, test>::value>::template
__enable_explicit<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >,
test>() || _CheckArgsConstructor<!_EnableImplicitReducedArityExtension && sizeof...(_Up) < sizeof...(_Tp) &&
!_PackExpandsToThisTuple<unique_ptr<__thread_struct, default_delete<__thread_struct> >, test>::value>::template
__enable_implicit<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >,
test>()' was not satisfied [with _Up = <std::__1::unique_ptr<std::__1::__thread_struct,
std::__1::default_delete<std::__1::__thread_struct> >, test>]
tuple(_Up&&... __u)
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/tuple:783:9: note: candidate template ignored: requirement
'_CheckArgsConstructor<sizeof...(_Up) == sizeof...(_Tp) && !_PackExpandsToThisTuple<>::value>::template
__enable_implicit<>()' was not satisfied [with _Alloc = test, _Up = <>]
tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u)
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/tuple:803:9: note: candidate template ignored: requirement
'_CheckArgsConstructor<sizeof...(_Up) == sizeof...(_Tp) && !_PackExpandsToThisTuple<>::value>::template
__enable_explicit<>()' was not satisfied [with _Alloc = test, _Up = <>]
tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u)
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/tuple:612:23: note: candidate constructor template not viable: requires
0 arguments, but 2 were provided
_LIBCPP_CONSTEXPR tuple()
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/tuple:677:7: note: candidate constructor template not viable: requires 4
arguments, but 2 were provided
tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t)
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/tuple:697:7: note: candidate constructor template not viable: requires 4
arguments, but 2 were provided
tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t)
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/tuple:822:9: note: candidate constructor template not viable: requires
single argument '__t', but 2 arguments were provided
tuple(_Tuple&& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, _Tuple>::value))
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/tuple:837:9: note: candidate constructor template not viable: requires
single argument '__t', but 2 arguments were provided
tuple(_Tuple&& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, _Tuple>::value))
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/tuple:850:9: note: candidate constructor template not viable: requires 3
arguments, but 2 were provided
tuple(allocator_arg_t, const _Alloc& __a, _Tuple&& __t)
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/tuple:864:9: note: candidate constructor template not viable: requires 3
arguments, but 2 were provided
tuple(allocator_arg_t, const _Alloc& __a, _Tuple&& __t)
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/tuple:615:5: note: candidate constructor not viable: requires 1
argument, but 2 were provided
tuple(tuple const&) = default;
^
In file included from test.cpp:1:
In file included from /Library/Developer/CommandLineTools/usr/include/c++/v1/iostream:38:
In file included from /Library/Developer/CommandLineTools/usr/include/c++/v1/ios:216:
In file included from /Library/Developer/CommandLineTools/usr/include/c++/v1/__locale:15:
In file included from /Library/Developer/CommandLineTools/usr/include/c++/v1/string:500:
In file included from /Library/Developer/CommandLineTools/usr/include/c++/v1/string_view:176:
In file included from /Library/Developer/CommandLineTools/usr/include/c++/v1/__string:56:
In file included from /Library/Developer/CommandLineTools/usr/include/c++/v1/algorithm:640:
In file included from /Library/Developer/CommandLineTools/usr/include/c++/v1/initializer_list:47:
In file included from /Library/Developer/CommandLineTools/usr/include/c++/v1/cstddef:110:
/Library/Developer/CommandLineTools/usr/include/c++/v1/type_traits:2360:12: error: call to implicitly-deleted copy constructor
of 'typename decay<test &>::type' (aka 'test')
return _VSTD::forward<_Tp>(__t);
^~~~~~~~~~~~~~~~~~~~~~~~
/Library/Developer/CommandLineTools/usr/include/c++/v1/__config:508:15: note: expanded from macro '_VSTD'
#define _VSTD std::_LIBCPP_NAMESPACE
^
/Library/Developer/CommandLineTools/usr/include/c++/v1/thread:366:21: note: in instantiation of function template
specialization 'std::__1::__decay_copy<test &>' requested here
__decay_copy(_VSTD::forward<_Fp>(__f)),
^
test.cpp:53:17: note: in instantiation of function template specialization 'std::__1::thread::thread<test &, void>' requested
here
std::thread t1{t}; // doesn't work
^
test.cpp:36:16: note: copy constructor of 'test' is implicitly deleted because field 'm1' has an inaccessible copy constructor
std::mutex m1;
^
2 errors generated.
This program fails to compile when I pass in the functor into the thread. But it works when I wrap it with std::ref
. It appears the class member mutex is the issue, but I am not sure why. Can someone explain why the std::ref
wrapper allows this to compile but without it, the program doesn't compile?
The compiler error message doesn't seem to help.
The default behaviour of thread
s is to make copies. Among other things, this prevents the general nastiness of having to synchronize the data across threads and the data going out of scope before the thread completes.
In this specific case, the object being copied contains a mutex
, and mutex
s cannot be copied or moved. A mutex
keeps multiple threads out of the same critical section of code. If different threads have different copies of the mutex
, they can all lock their copy and enter the critical section, rendering the mutex
useless. They must all share the same mutex
, and in this case this means all threads must all share the same test
.
In this case a static
mutex m1
would be a viable solution in addition to passing by reference.
Note: Because i
is public
and accessible to anyone, i
can easily be accessed by anyone regardless of the mutex
.
Note: Prefer to use a std::lock_guard
or a std::scoped_lock
instead of manually calling lock and unlock manually. A lock_guard
or scoped_lock
locks the mutex
on construction and unlocks on destruction, guaranteeing the mutex
will be unlocked when the locking object goes out of scope.
Note: Removing the mutex
and using std::atomic<int>
in place of int
should solve most synchronization problems.