在 C++11 中使用 condition_variable 的信号量实现

Semaphore implementation using condition_variable in C++11

我正在尝试在 C++11 中实现计数信号量。这是我的试炼...

#include <iostream>
#include <thread>
#include <mutex>
#include <future>
#include <vector>
using namespace std;

class Semaphore{
private:
  int count;
  condition_variable cv;
  mutex mtx;

public:

  Semaphore(int count_):count(count_){}
  void take(){
    unique_lock<mutex> lck(mtx);
    while(count == 0)
      cv.wait(lck);
    count--;
    cout << "Take\n";
  }
  void release(){
    unique_lock<mutex> lck(mtx);
    count++;
    cout << "Release\n";
    cv.notify_one();
  }

};
int main() {
  Semaphore sem(5);

  vector<thread> threads;
  for(int i = 0; i < 10; i++){
    threads.push_back(thread(&Semaphore::release, sem));
  }
  for(int i = 0; i < 10; i++){
    threads.push_back(thread(&Semaphore::release, sem));
  }
  for(int i = 0; i < threads.size(); i++)
      threads[i].join();
  return 0;

}

但是,编译时出现以下错误...

note: 'Semaphore::Semaphore(Semaphore&&)' is implicitly deleted because the default definition would be ill-formed:
     class Semaphore{

我最好的猜测是,这是因为在 class 中使用了 condition_variable,它既不可复制也不可移动,因此当它作为参数传递给 [=23] 时会导致问题=].但是,我不知道如何解决这个问题。有什么线索吗?

更新: 这是完整的错误日志...

In file included from /usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/functional:55:0,
                 from /usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/thread:39,
                 from /Users/emostafa/Desktop/cpp/A.cpp:2:
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/tuple: In instantiation of 'constexpr std::_Head_base<_Idx, _Head, false>::_Head_base(_UHead&&) [with _UHead = Semaphore; long unsigned int _Idx = 1ul; _Head = Semaphore]':
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/tuple:369:49:   required from 'constexpr std::_Tuple_impl<_Idx, _Head>::_Tuple_impl(std::_Tuple_impl<_Idx, _Head>&&) [with long unsigned int _Idx = 1ul; _Head = Semaphore]'
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/type_traits:1162:12:   required from 'struct std::__is_nt_constructible_impl<std::_Tuple_impl<1ul, Semaphore>, std::_Tuple_impl<1ul, Semaphore>&&>'
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/type_traits:137:12:   required from 'struct std::__and_<std::is_constructible<std::_Tuple_impl<1ul, Semaphore>, std::_Tuple_impl<1ul, Semaphore>&&>, std::__is_nt_constructible_impl<std::_Tuple_impl<1ul, Semaphore>, std::_Tuple_impl<1ul, Semaphore>&&> >'
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/type_traits:1174:12:   required from 'struct std::is_nothrow_constructible<std::_Tuple_impl<1ul, Semaphore>, std::_Tuple_impl<1ul, Semaphore>&&>'
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/type_traits:1205:12:   required from 'struct std::__is_nothrow_move_constructible_impl<std::_Tuple_impl<1ul, Semaphore>, true>'
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/type_traits:1211:12:   required from 'struct std::is_nothrow_move_constructible<std::_Tuple_impl<1ul, Semaphore> >'
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/type_traits:137:12:   required from 'struct std::__and_<std::is_nothrow_move_constructible<std::_Mem_fn<void (Semaphore::*)()> >, std::is_nothrow_move_constructible<std::_Tuple_impl<1ul, Semaphore> > >'
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/tuple:218:7:   required from 'constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(std::_Tuple_impl<_Idx, _Head, _Tail ...>&&) [with long unsigned int _Idx = 0ul; _Head = std::_Mem_fn<void (Semaphore::*)()>; _Tail = {Semaphore}]'
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/functional:1559:41:   required from 'typename std::_Bind_simple_helper<_Func, _BoundArgs>::__type std::__bind_simple(_Callable&&, _Args&& ...) [with _Callable = void (Semaphore::*)(); _Args = {Semaphore&}; typename std::_Bind_simple_helper<_Func, _BoundArgs>::__type = std::_Bind_simple<std::_Mem_fn<void (Semaphore::*)()>(Semaphore)>]'
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/thread:142:59:   required from 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (Semaphore::*)(); _Args = {Semaphore&}]'
/Users/emostafa/Desktop/cpp/A.cpp:37:54:   required from here
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/tuple:115:42: error: use of deleted function 'Semaphore::Semaphore(Semaphore&&)'
  : _M_head_impl(std::forward<_UHead>(__h)) { }
                                          ^
/Users/emostafa/Desktop/cpp/A.cpp:9:7: note: 'Semaphore::Semaphore(Semaphore&&)' is implicitly deleted because the default definition would be ill-formed:
 class Semaphore{
       ^
/Users/emostafa/Desktop/cpp/A.cpp:9:7: error: use of deleted function 'std::condition_variable::condition_variable(const std::condition_variable&)'
In file included from /usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/future:41:0,
                 from /Users/emostafa/Desktop/cpp/A.cpp:4:
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/condition_variable:81:5: note: declared here
     condition_variable(const condition_variable&) = delete;
     ^
/Users/emostafa/Desktop/cpp/A.cpp:9:7: error: use of deleted function 'std::mutex::mutex(const std::mutex&)'
 class Semaphore{
       ^
In file included from /Users/emostafa/Desktop/cpp/A.cpp:3:0:
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/mutex:129:5: note: declared here
     mutex(const mutex&) = delete;
     ^
In file included from /usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/functional:55:0,
                 from /usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/thread:39,
                 from /Users/emostafa/Desktop/cpp/A.cpp:2:
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/tuple: In instantiation of 'constexpr std::_Head_base<_Idx, _Head, false>::_Head_base(const _Head&) [with long unsigned int _Idx = 1ul; _Head = Semaphore]':
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/tuple:357:21:   required from 'constexpr std::_Tuple_impl<_Idx, _Head>::_Tuple_impl(const _Head&) [with long unsigned int _Idx = 1ul; _Head = Semaphore]'
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/tuple:206:44:   required from 'constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(const _Head&, const _Tail& ...) [with long unsigned int _Idx = 0ul; _Head = std::_Mem_fn<void (Semaphore::*)()>; _Tail = {Semaphore}]'
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/tuple:606:30:   required from 'constexpr std::tuple<_T1, _T2>::tuple(const _T1&, const _T2&) [with _T1 = std::_Mem_fn<void (Semaphore::*)()>; _T2 = Semaphore]'
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/functional:1510:72:   required from 'std::_Bind_simple<_Callable(_Args ...)>::_Bind_simple(_Tp&&, _Up&& ...) [with _Tp = std::_Mem_fn<void (Semaphore::*)()>; _Up = {Semaphore&}; _Callable = std::_Mem_fn<void (Semaphore::*)()>; _Args = {Semaphore}]'
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/functional:1559:41:   required from 'typename std::_Bind_simple_helper<_Func, _BoundArgs>::__type std::__bind_simple(_Callable&&, _Args&& ...) [with _Callable = void (Semaphore::*)(); _Args = {Semaphore&}; typename std::_Bind_simple_helper<_Func, _BoundArgs>::__type = std::_Bind_simple<std::_Mem_fn<void (Semaphore::*)()>(Semaphore)>]'
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/thread:142:59:   required from 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (Semaphore::*)(); _Args = {Semaphore&}]'
/Users/emostafa/Desktop/cpp/A.cpp:37:54:   required from here
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/tuple:108:25: error: use of deleted function 'Semaphore::Semaphore(const Semaphore&)'
       : _M_head_impl(__h) { }
                         ^
/Users/emostafa/Desktop/cpp/A.cpp:9:7: note: 'Semaphore::Semaphore(const Semaphore&)' is implicitly deleted because the default definition would be ill-formed:
 class Semaphore{
       ^
/Users/emostafa/Desktop/cpp/A.cpp:9:7: error: use of deleted function 'std::condition_variable::condition_variable(const std::condition_variable&)'
In file included from /usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/future:41:0,
                 from /Users/emostafa/Desktop/cpp/A.cpp:4:
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/condition_variable:81:5: note: declared here
     condition_variable(const condition_variable&) = delete;
     ^
/Users/emostafa/Desktop/cpp/A.cpp:9:7: error: use of deleted function 'std::mutex::mutex(const std::mutex&)'
 class Semaphore{
       ^
In file included from /Users/emostafa/Desktop/cpp/A.cpp:3:0:
/usr/local/Cellar/gcc/5.3.0/include/c++/5.3.0/mutex:129:5: note: declared here
     mutex(const mutex&) = delete;

您将 sem 对象作为 传递给 thread 构造函数。这需要复制它,这就是'use of deleted function'所指的。

如果您希望线程、任务、异步上下文...引用您的信号量,要么通过 std::ref(sem) 传递它,要么回退到普通的旧指针并将其传递给它的地址: &sem.