|
|
@ -35,29 +35,28 @@ |
|
|
|
|
|
|
|
|
|
|
|
namespace grpc { |
|
|
|
namespace grpc { |
|
|
|
|
|
|
|
|
|
|
|
#ifdef __GNUC__ |
|
|
|
|
|
|
|
#if (__GNUC__ * 100 + __GNUC_MINOR__ < 406) |
|
|
|
|
|
|
|
#define GRPC_NO_NULLPTR |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef GRPC_NO_NULLPTR |
|
|
|
|
|
|
|
#include <memory> |
|
|
|
|
|
|
|
const class { |
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
template <class T> operator T*() const {return static_cast<T *>(0);} |
|
|
|
|
|
|
|
template <class T> operator std::unique_ptr<T>() const { |
|
|
|
|
|
|
|
return std::unique_ptr<T>(static_cast<T *>(0)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
operator bool() const {return false;} |
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
void operator&() const = delete; |
|
|
|
|
|
|
|
} nullptr = {}; |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ThreadPool::ThreadPool(int num_threads) : shutdown_(false) { |
|
|
|
ThreadPool::ThreadPool(int num_threads) : shutdown_(false) { |
|
|
|
for (int i = 0; i < num_threads; i++) { |
|
|
|
for (int i = 0; i < num_threads; i++) { |
|
|
|
threads_.push_back(std::thread(&ThreadPool::ThreadFunc, this)); |
|
|
|
threads_.push_back(std::thread([this]() { |
|
|
|
|
|
|
|
for (;;) { |
|
|
|
|
|
|
|
// Wait until work is available or we are shutting down.
|
|
|
|
|
|
|
|
auto have_work = [this]() { return shutdown_ || !callbacks_.empty(); }; |
|
|
|
|
|
|
|
std::unique_lock<std::mutex> lock(mu_); |
|
|
|
|
|
|
|
if (!have_work()) { |
|
|
|
|
|
|
|
cv_.wait(lock, have_work); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Drain callbacks before considering shutdown to ensure all work
|
|
|
|
|
|
|
|
// gets completed.
|
|
|
|
|
|
|
|
if (!callbacks_.empty()) { |
|
|
|
|
|
|
|
auto cb = callbacks_.front(); |
|
|
|
|
|
|
|
callbacks_.pop(); |
|
|
|
|
|
|
|
lock.unlock(); |
|
|
|
|
|
|
|
cb(); |
|
|
|
|
|
|
|
} else if (shutdown_) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
})); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|