Skip to content

Instantly share code, notes, and snippets.

@astarasikov
Created April 23, 2013 19:09
Show Gist options
  • Save astarasikov/5446478 to your computer and use it in GitHub Desktop.
Save astarasikov/5446478 to your computer and use it in GitHub Desktop.
C++ Resource Pool Implementation
#include <cstdio>
#include <pthread.h>
#define cas __sync_bool_compare_and_swap
#define TEST_MUTEX 0
#if TEST_MUTEX
#define MUTEX_TEST(x) x
#else
#define MUTEX_TEST(x)
#endif
class Mutex {
protected:
int _state;
MUTEX_TEST(int _locked;)
public:
Mutex() : _state(0) {
MUTEX_TEST(_locked = 0;)
}
void lock() {
while (!cas(&_state, 0, 1)) {
}
MUTEX_TEST(
if (_locked) {
printf("%s: error, already locked! %d\n", __func__, _locked);
}
else {
puts("ok");
}
_locked++;
)
}
void unlock() {
MUTEX_TEST(_locked = 0;)
_state = 0;
}
};
class Semaphore {
protected:
int _value;
Mutex _sync;
Mutex _wait;
public:
Semaphore(int initial) :
_value(initial),
_sync(Mutex()), _wait(Mutex()) {}
void down() {
_sync.lock();
_value--;
if (_value >= 0) {
_sync.unlock();
}
else {
_sync.unlock();
_wait.lock();
}
}
void up() {
_sync.lock();
_value++;
if (_value <= 0) {
_wait.unlock();
}
_sync.unlock();
}
};
template<class T>
class Allocator {
public:
virtual ~Allocator() {};
virtual T* alloc() = 0;
virtual void free(T* t) = 0;
};
template<class T>
class Pool {
protected:
int _capacity;
T **data;
int _tail;
Allocator<T> *_alloc;
Semaphore _sem;
Mutex _mtx;
public:
Pool(Allocator<T> *alloc, int capacity) :
_capacity(capacity),
data(new T*[_capacity]),
_tail(_capacity - 1),
_alloc(alloc),
_sem(Semaphore(_capacity)),
_mtx(Mutex())
{
for (int i = 0; i < _capacity; i++) {
data[i] = _alloc->alloc();
}
}
virtual ~Pool() {
for (int i = 0; i < _capacity; i++) {
_alloc->free(data[i]);
}
delete[] data;
}
T* get(void) {
T *ret = NULL;
_sem.down();
_mtx.lock();
if (_tail >= 0 && _tail <_capacity) {
ret = data[_tail];
_tail--;
}
_mtx.unlock();
return ret;
}
void release(T* item) {
_mtx.lock();
if (_tail < _capacity - 1) {
data[_tail + 1] = item;
_tail++;
_sem.up();
}
_mtx.unlock();
}
};
#define N_THREADS 10
#define POOL_SIZE 100
class IntAllocator : public Allocator<int> {
virtual int* alloc() {
return new int(42);
}
virtual void free(int *i) {
delete i;
}
};
static IntAllocator alloc;
static Pool<int> pool(&alloc, POOL_SIZE);
static void *test_thread(void *data) {
for (int i = 0; i < POOL_SIZE; i++) {
int *d = pool.get();
if (d) {
printf("%s: got %d\n", __func__, *d);
}
else {
printf("%s: NULL\n", __func__);
}
pool.release(d);
}
return NULL;
}
#include <cstdlib>
#include <unistd.h>
static Mutex mtx;
static void *test_mutex(void *data) {
srand(time(0));
while (1) {
mtx.lock();
usleep(rand() % 10000);
mtx.unlock();
}
return NULL;
}
int main() {
pthread_t threads[N_THREADS];
for (int i = 0; i < N_THREADS; i++) {
pthread_create(threads + i, NULL, test_thread, NULL);
}
while (1) {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment