122 lines
3.6 KiB
C
122 lines
3.6 KiB
C
|
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||
|
// This source code is licensed under the BSD-style license found in the
|
||
|
// LICENSE file in the root directory of this source tree. An additional grant
|
||
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||
|
//
|
||
|
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <memory>
|
||
|
#include <functional>
|
||
|
#include <type_traits>
|
||
|
|
||
|
namespace rocksdb {
|
||
|
namespace port {
|
||
|
|
||
|
// This class is a replacement for std::thread
|
||
|
// 2 reasons we do not like std::thread:
|
||
|
// -- is that it dynamically allocates its internals that are automatically
|
||
|
// freed when the thread terminates and not on the destruction of the
|
||
|
// object. This makes it difficult to control the source of memory
|
||
|
// allocation
|
||
|
// - This implements Pimpl so we can easily replace the guts of the
|
||
|
// object in our private version if necessary.
|
||
|
class WindowsThread {
|
||
|
|
||
|
struct Data;
|
||
|
|
||
|
std::unique_ptr<Data> data_;
|
||
|
unsigned int th_id_;
|
||
|
|
||
|
void Init(std::function<void()>&&);
|
||
|
|
||
|
public:
|
||
|
|
||
|
typedef void* native_handle_type;
|
||
|
|
||
|
// Construct with no thread
|
||
|
WindowsThread();
|
||
|
|
||
|
// Template constructor
|
||
|
//
|
||
|
// This templated constructor accomplishes several things
|
||
|
//
|
||
|
// - Allows the class as whole to be not a template
|
||
|
//
|
||
|
// - take "universal" references to support both _lvalues and _rvalues
|
||
|
//
|
||
|
// - because this constructor is a catchall case in many respects it
|
||
|
// may prevent us from using both the default __ctor, the move __ctor.
|
||
|
// Also it may circumvent copy __ctor deletion. To work around this
|
||
|
// we make sure this one has at least one argument and eliminate
|
||
|
// it from the overload selection when WindowsThread is the first
|
||
|
// argument.
|
||
|
//
|
||
|
// - construct with Fx(Ax...) with a variable number of types/arguments.
|
||
|
//
|
||
|
// - Gathers together the callable object with its arguments and constructs
|
||
|
// a single callable entity
|
||
|
//
|
||
|
// - Makes use of std::function to convert it to a specification-template
|
||
|
// dependent type that both checks the signature conformance to ensure
|
||
|
// that all of the necessary arguments are provided and allows pimpl
|
||
|
// implementation.
|
||
|
template<class Fn,
|
||
|
class... Args,
|
||
|
class = typename std::enable_if<
|
||
|
!std::is_same<typename std::decay<Fn>::type,
|
||
|
WindowsThread>::value>::type>
|
||
|
explicit WindowsThread(Fn&& fx, Args&&... ax) :
|
||
|
WindowsThread() {
|
||
|
|
||
|
// Use binder to create a single callable entity
|
||
|
auto binder = std::bind(std::forward<Fn>(fx),
|
||
|
std::forward<Args>(ax)...);
|
||
|
// Use std::function to take advantage of the type erasure
|
||
|
// so we can still hide implementation within pimpl
|
||
|
// This also makes sure that the binder signature is compliant
|
||
|
std::function<void()> target = binder;
|
||
|
|
||
|
Init(std::move(target));
|
||
|
}
|
||
|
|
||
|
|
||
|
~WindowsThread();
|
||
|
|
||
|
WindowsThread(const WindowsThread&) = delete;
|
||
|
|
||
|
WindowsThread& operator=(const WindowsThread&) = delete;
|
||
|
|
||
|
WindowsThread(WindowsThread&&) noexcept;
|
||
|
|
||
|
WindowsThread& operator=(WindowsThread&&) noexcept;
|
||
|
|
||
|
bool joinable() const;
|
||
|
|
||
|
unsigned int get_id() const { return th_id_; }
|
||
|
|
||
|
native_handle_type native_handle() const;
|
||
|
|
||
|
static unsigned hardware_concurrency();
|
||
|
|
||
|
void join();
|
||
|
|
||
|
bool detach();
|
||
|
|
||
|
void swap(WindowsThread&);
|
||
|
};
|
||
|
} // namespace port
|
||
|
} // namespace rocksdb
|
||
|
|
||
|
namespace std {
|
||
|
inline
|
||
|
void swap(rocksdb::port::WindowsThread& th1,
|
||
|
rocksdb::port::WindowsThread& th2) {
|
||
|
th1.swap(th2);
|
||
|
}
|
||
|
} // namespace std
|
||
|
|