rocksdb/port/win/win_thread.h
Dmitri Smirnov 0a4cdde50a Windows thread
Summary:
introduce new methods into a public threadpool interface,
- allow submission of std::functions as they allow greater flexibility.
- add Joining methods to the implementation to join scheduled and submitted jobs with
  an option to cancel jobs that did not start executing.
- Remove ugly `#ifdefs` between pthread and std implementation, make it uniform.
- introduce pimpl for a drop in replacement of the implementation
- Introduce rocksdb::port::Thread typedef which is a replacement for std::thread.  On Posix Thread defaults as before std::thread.
- Implement WindowsThread that allocates memory in a more controllable manner than windows std::thread with a replaceable implementation.
- should be no functionality changes.
Closes https://github.com/facebook/rocksdb/pull/1823

Differential Revision: D4492902

Pulled By: siying

fbshipit-source-id: c74cb11
2017-02-06 14:54:18 -08:00

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