Created
April 23, 2013 19:09
-
-
Save astarasikov/5446478 to your computer and use it in GitHub Desktop.
C++ Resource Pool Implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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