dispenso
A library for task parallelism
Loading...
Searching...
No Matches
resource_pool.h
Go to the documentation of this file.
1
/*
2
* Copyright (c) Meta Platforms, Inc. and affiliates.
3
*
4
* This source code is licensed under the MIT license found in the
5
* LICENSE file in the root directory of this source tree.
6
*/
7
14
#pragma once
15
16
#include <dispenso/platform.h>
17
#include <
dispenso/tsan_annotations.h
>
18
#include <moodycamel/blockingconcurrentqueue.h>
19
20
namespace
dispenso {
21
22
template
<
typename
T>
23
class
ResourcePool;
24
29
template
<
typename
T>
30
class
Resource
{
31
public
:
32
Resource
(
Resource
&& other) : resource_(other.resource_), pool_(other.pool_) {
33
other.resource_ =
nullptr
;
34
}
35
36
Resource
& operator=(
Resource
&& other) {
37
if
(&other !=
this
) {
38
recycle();
39
resource_ = other.resource_;
40
pool_ = other.pool_;
41
other.resource_ =
nullptr
;
42
}
43
return
*
this
;
44
}
45
51
T&
get
() {
52
return
*resource_;
53
}
54
55
~Resource
() {
56
recycle();
57
}
58
59
private
:
60
Resource(T* res, ResourcePool<T>* pool) : resource_(res), pool_(pool) {}
61
62
void
recycle();
63
64
T* resource_;
65
ResourcePool<T>* pool_;
66
67
friend
class
ResourcePool<T>;
68
};
69
74
template
<
typename
T>
75
class
ResourcePool
{
76
public
:
84
template
<
typename
F>
85
ResourcePool
(
size_t
size,
const
F& init)
86
: pool_(size),
87
backingResources_(
88
reinterpret_cast<char*>(
89
detail::alignedMalloc(size * detail::alignToCacheLine(sizeof(T))))),
90
size_(size) {
91
char
* buf = backingResources_;
92
93
// There are three reasons we create our own buffer and use placement new:
94
// 1. We want to be able to handle non-movable non-copyable objects
95
// * Note that we could do this with std::deque
96
// 2. We want to minimize memory allocations, since that can be a common point of contention in
97
// multithreaded programs.
98
// 3. We can easily ensure that the objects are cache aligned to help avoid false sharing.
99
100
for
(
size_t
i = 0; i < size; ++i) {
101
pool_.enqueue(
new
(buf) T(init()));
102
buf += detail::alignToCacheLine(
sizeof
(T));
103
}
104
}
105
111
Resource<T>
acquire
() {
112
T* t;
113
DISPENSO_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN();
114
pool_.wait_dequeue(t);
115
DISPENSO_TSAN_ANNOTATE_IGNORE_WRITES_END();
116
return
Resource<T>
(t,
this
);
117
}
118
123
~ResourcePool
() {
124
assert(pool_.size_approx() == size_);
125
for
(
size_t
i = 0; i < size_; ++i) {
126
T* t;
127
DISPENSO_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN();
128
pool_.wait_dequeue(t);
129
DISPENSO_TSAN_ANNOTATE_IGNORE_WRITES_END();
130
t->~T();
131
}
132
detail::alignedFree(backingResources_);
133
}
134
135
private
:
136
void
recycle(T* t) {
137
DISPENSO_TSAN_ANNOTATE_IGNORE_WRITES_BEGIN();
138
pool_.enqueue(t);
139
DISPENSO_TSAN_ANNOTATE_IGNORE_WRITES_END();
140
}
141
142
moodycamel::BlockingConcurrentQueue<T*> pool_;
143
char
* backingResources_;
144
size_t
size_;
145
146
friend
class
Resource<T>;
147
};
148
149
template
<
typename
T>
150
void
Resource<T>::recycle() {
151
if
(resource_) {
152
pool_->recycle(resource_);
153
}
154
}
155
156
}
// namespace dispenso
dispenso::Resource
Definition
resource_pool.h:30
dispenso::Resource::get
T & get()
Definition
resource_pool.h:51
dispenso::ResourcePool
Definition
resource_pool.h:75
dispenso::ResourcePool::~ResourcePool
~ResourcePool()
Definition
resource_pool.h:123
dispenso::ResourcePool::acquire
Resource< T > acquire()
Definition
resource_pool.h:111
dispenso::ResourcePool::ResourcePool
ResourcePool(size_t size, const F &init)
Definition
resource_pool.h:85
tsan_annotations.h
dispenso
resource_pool.h
Generated by
1.12.0