mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-04-23 10:09:36 +08:00
Replace pointers by values or unique_ptr for better leak-safety
This commit is contained in:
parent
39335cf51e
commit
a709c8efb4
@ -58,11 +58,9 @@ class ThreadPoolTempl : public Eigen::ThreadPoolInterface {
|
|||||||
coprimes_.push_back(i);
|
coprimes_.push_back(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
queues_.resize(num_threads_);
|
||||||
for (int i = 0; i < num_threads_; i++) {
|
for (int i = 0; i < num_threads_; i++) {
|
||||||
queues_.push_back(new Queue());
|
threads_.emplace_back(env_.CreateThread([this, i]() { WorkerLoop(i); }));
|
||||||
}
|
|
||||||
for (int i = 0; i < num_threads_; i++) {
|
|
||||||
threads_.push_back(env_.CreateThread([this, i]() { WorkerLoop(i); }));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,13 +76,12 @@ class ThreadPoolTempl : public Eigen::ThreadPoolInterface {
|
|||||||
// Since we were cancelled, there might be entries in the queues.
|
// Since we were cancelled, there might be entries in the queues.
|
||||||
// Empty them to prevent their destructor from asserting.
|
// Empty them to prevent their destructor from asserting.
|
||||||
for (size_t i = 0; i < queues_.size(); i++) {
|
for (size_t i = 0; i < queues_.size(); i++) {
|
||||||
queues_[i]->Flush();
|
queues_[i].Flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join threads explicitly to avoid destruction order issues.
|
// Join threads explicitly to avoid destruction order issues.
|
||||||
for (size_t i = 0; i < num_threads_; i++) delete threads_[i];
|
threads_.resize(0);
|
||||||
for (size_t i = 0; i < num_threads_; i++) delete queues_[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Schedule(std::function<void()> fn) {
|
void Schedule(std::function<void()> fn) {
|
||||||
@ -92,13 +89,13 @@ class ThreadPoolTempl : public Eigen::ThreadPoolInterface {
|
|||||||
PerThread* pt = GetPerThread();
|
PerThread* pt = GetPerThread();
|
||||||
if (pt->pool == this) {
|
if (pt->pool == this) {
|
||||||
// Worker thread of this pool, push onto the thread's queue.
|
// Worker thread of this pool, push onto the thread's queue.
|
||||||
Queue* q = queues_[pt->thread_id];
|
Queue& q = queues_[pt->thread_id];
|
||||||
t = q->PushFront(std::move(t));
|
t = q.PushFront(std::move(t));
|
||||||
} else {
|
} else {
|
||||||
// A free-standing thread (or worker of another pool), push onto a random
|
// A free-standing thread (or worker of another pool), push onto a random
|
||||||
// queue.
|
// queue.
|
||||||
Queue* q = queues_[Rand(&pt->rand) % queues_.size()];
|
Queue& q = queues_[Rand(&pt->rand) % queues_.size()];
|
||||||
t = q->PushBack(std::move(t));
|
t = q.PushBack(std::move(t));
|
||||||
}
|
}
|
||||||
// Note: below we touch this after making w available to worker threads.
|
// Note: below we touch this after making w available to worker threads.
|
||||||
// Strictly speaking, this can lead to a racy-use-after-free. Consider that
|
// Strictly speaking, this can lead to a racy-use-after-free. Consider that
|
||||||
@ -157,8 +154,8 @@ class ThreadPoolTempl : public Eigen::ThreadPoolInterface {
|
|||||||
Environment env_;
|
Environment env_;
|
||||||
const int num_threads_;
|
const int num_threads_;
|
||||||
const bool allow_spinning_;
|
const bool allow_spinning_;
|
||||||
MaxSizeVector<Thread*> threads_;
|
MaxSizeVector<std::unique_ptr<Thread> > threads_;
|
||||||
MaxSizeVector<Queue*> queues_;
|
MaxSizeVector<Queue> queues_;
|
||||||
MaxSizeVector<unsigned> coprimes_;
|
MaxSizeVector<unsigned> coprimes_;
|
||||||
MaxSizeVector<EventCount::Waiter> waiters_;
|
MaxSizeVector<EventCount::Waiter> waiters_;
|
||||||
std::atomic<unsigned> blocked_;
|
std::atomic<unsigned> blocked_;
|
||||||
@ -173,7 +170,7 @@ class ThreadPoolTempl : public Eigen::ThreadPoolInterface {
|
|||||||
pt->pool = this;
|
pt->pool = this;
|
||||||
pt->rand = std::hash<std::thread::id>()(std::this_thread::get_id());
|
pt->rand = std::hash<std::thread::id>()(std::this_thread::get_id());
|
||||||
pt->thread_id = thread_id;
|
pt->thread_id = thread_id;
|
||||||
Queue* q = queues_[thread_id];
|
Queue& q = queues_[thread_id];
|
||||||
EventCount::Waiter* waiter = &waiters_[thread_id];
|
EventCount::Waiter* waiter = &waiters_[thread_id];
|
||||||
// TODO(dvyukov,rmlarsen): The time spent in Steal() is proportional
|
// TODO(dvyukov,rmlarsen): The time spent in Steal() is proportional
|
||||||
// to num_threads_ and we assume that new work is scheduled at a
|
// to num_threads_ and we assume that new work is scheduled at a
|
||||||
@ -189,10 +186,10 @@ class ThreadPoolTempl : public Eigen::ThreadPoolInterface {
|
|||||||
// counter-productive for the types of I/O workloads the single thread
|
// counter-productive for the types of I/O workloads the single thread
|
||||||
// pools tend to be used for.
|
// pools tend to be used for.
|
||||||
while (!cancelled_) {
|
while (!cancelled_) {
|
||||||
Task t = q->PopFront();
|
Task t = q.PopFront();
|
||||||
for (int i = 0; i < spin_count && !t.f; i++) {
|
for (int i = 0; i < spin_count && !t.f; i++) {
|
||||||
if (!cancelled_.load(std::memory_order_relaxed)) {
|
if (!cancelled_.load(std::memory_order_relaxed)) {
|
||||||
t = q->PopFront();
|
t = q.PopFront();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!t.f) {
|
if (!t.f) {
|
||||||
@ -206,7 +203,7 @@ class ThreadPoolTempl : public Eigen::ThreadPoolInterface {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (!cancelled_) {
|
while (!cancelled_) {
|
||||||
Task t = q->PopFront();
|
Task t = q.PopFront();
|
||||||
if (!t.f) {
|
if (!t.f) {
|
||||||
t = Steal();
|
t = Steal();
|
||||||
if (!t.f) {
|
if (!t.f) {
|
||||||
@ -243,7 +240,7 @@ class ThreadPoolTempl : public Eigen::ThreadPoolInterface {
|
|||||||
unsigned inc = coprimes_[r % coprimes_.size()];
|
unsigned inc = coprimes_[r % coprimes_.size()];
|
||||||
unsigned victim = r % size;
|
unsigned victim = r % size;
|
||||||
for (unsigned i = 0; i < size; i++) {
|
for (unsigned i = 0; i < size; i++) {
|
||||||
Task t = queues_[victim]->PopBack();
|
Task t = queues_[victim].PopBack();
|
||||||
if (t.f) {
|
if (t.f) {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
@ -270,7 +267,7 @@ class ThreadPoolTempl : public Eigen::ThreadPoolInterface {
|
|||||||
if (cancelled_) {
|
if (cancelled_) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
*t = queues_[victim]->PopBack();
|
*t = queues_[victim].PopBack();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -278,7 +275,8 @@ class ThreadPoolTempl : public Eigen::ThreadPoolInterface {
|
|||||||
// If we are shutting down and all worker threads blocked without work,
|
// If we are shutting down and all worker threads blocked without work,
|
||||||
// that's we are done.
|
// that's we are done.
|
||||||
blocked_++;
|
blocked_++;
|
||||||
if (done_ && blocked_ == num_threads_) {
|
// TODO is blocked_ required to be unsigned?
|
||||||
|
if (done_ && blocked_ == static_cast<unsigned>(num_threads_)) {
|
||||||
ec_.CancelWait(waiter);
|
ec_.CancelWait(waiter);
|
||||||
// Almost done, but need to re-check queues.
|
// Almost done, but need to re-check queues.
|
||||||
// Consider that all queues are empty and all worker threads are preempted
|
// Consider that all queues are empty and all worker threads are preempted
|
||||||
@ -311,7 +309,7 @@ class ThreadPoolTempl : public Eigen::ThreadPoolInterface {
|
|||||||
unsigned inc = coprimes_[r % coprimes_.size()];
|
unsigned inc = coprimes_[r % coprimes_.size()];
|
||||||
unsigned victim = r % size;
|
unsigned victim = r % size;
|
||||||
for (unsigned i = 0; i < size; i++) {
|
for (unsigned i = 0; i < size; i++) {
|
||||||
if (!queues_[victim]->Empty()) {
|
if (!queues_[victim].Empty()) {
|
||||||
return victim;
|
return victim;
|
||||||
}
|
}
|
||||||
victim += inc;
|
victim += inc;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user