rocksdb/port/win/win_thread.h

118 lines
3.7 KiB
C++

// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root 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
#ifndef _POSIX_THREADS
#include <functional>
#include <memory>
#include <type_traits>
#include "rocksdb/rocksdb_namespace.h"
namespace ROCKSDB_NAMESPACE {
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::shared_ptr<Data> data_;
unsigned int th_id_;
void Init(std::function<void()>&&);
public:
using native_handle_type = void*;
// 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
namespace std {
inline void swap(ROCKSDB_NAMESPACE::port::WindowsThread& th1,
ROCKSDB_NAMESPACE::port::WindowsThread& th2) {
th1.swap(th2);
}
} // namespace std
#endif // !_POSIX_THREADS