Created
June 8, 2012 15:04
-
-
Save fcamel/2896063 to your computer and use it in GitHub Desktop.
Lock-free queue test
This file contains hidden or 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
/* | |
# compilation | |
$ g++ queue.cpp -O2 -g -pthread -o queue_without_lock -DLOCK_FREE | |
$ g++ queue.cpp -O2 -g -pthread -o queue_with_lock | |
# execution time | |
$ time ./queue_with_lock | |
real 0m0.035s 0m0.153s 0m0.055s | |
user 0m0.040s 0m0.270s 0m0.070s | |
sys 0m0.020s 0m0.030s 0m0.030s | |
$ time ./queue_without_lock | |
real 0m0.007s 0m0.007s 0m0.009s | |
user 0m0.010s 0m0.010s 0m0.010s | |
sys 0m0.000s 0m0.000s 0m0.000s | |
*/ | |
#include <cstdio> | |
#include <pthread.h> | |
#include <unistd.h> | |
static const int QUEUE_SIZE = 10; | |
static const int TEST_ROUND = 100000; | |
//#define LOCK_FREE | |
class ScopeLock | |
{ | |
public: | |
ScopeLock(pthread_mutex_t* mutex) : m_mutex(mutex) | |
{ | |
pthread_mutex_lock(mutex); | |
} | |
~ScopeLock() | |
{ | |
pthread_mutex_unlock(m_mutex); | |
} | |
private: | |
pthread_mutex_t *m_mutex; | |
}; | |
template <typename T> | |
class Queue | |
{ | |
public: | |
Queue() : m_head(0) | |
, m_tail(0) | |
{ | |
#ifndef LOCK_FREE | |
pthread_mutexattr_t attr; | |
pthread_mutexattr_init(&attr); | |
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); | |
pthread_mutex_init(&m_mutex, &attr); | |
pthread_mutexattr_destroy(&attr); | |
#endif | |
} | |
~Queue() | |
{ | |
} | |
bool append(T val) | |
{ | |
#ifndef LOCK_FREE | |
ScopeLock lock(&m_mutex); | |
#endif | |
if (is_full()) { | |
return false; | |
} | |
m_data[m_tail] = val; | |
m_tail = (m_tail + 1) % QUEUE_SIZE; | |
return true; | |
} | |
bool pop(T* val) | |
{ | |
#ifndef LOCK_FREE | |
ScopeLock lock(&m_mutex); | |
#endif | |
if (is_empty()) { | |
return false; | |
} | |
*val = m_data[m_head]; | |
m_head = (m_head + 1) % QUEUE_SIZE; | |
return true; | |
} | |
private: | |
bool is_full() | |
{ | |
return ((m_tail + 1 + QUEUE_SIZE) % QUEUE_SIZE) == m_head; | |
} | |
bool is_empty() | |
{ | |
return m_head == m_tail; | |
} | |
#ifdef LOCK_FREE | |
volatile int m_head; | |
volatile int m_tail; | |
#else | |
int m_head; | |
int m_tail; | |
pthread_mutex_t m_mutex; | |
#endif | |
T m_data[QUEUE_SIZE]; | |
}; | |
void* producer(void *arg) | |
{ | |
Queue<int> *queue = (Queue<int>*)arg; | |
for (int i = 1; i <= TEST_ROUND; ) { | |
if (queue->append(i)) { | |
i++; | |
} | |
} | |
return 0; | |
} | |
void consumer(void *arg) | |
{ | |
Queue<int> *queue = (Queue<int>*)arg; | |
long long sum = 0; | |
int val; | |
bool result; | |
for (int i = 1; i <= TEST_ROUND; i++) { | |
do { | |
result = queue->pop(&val); | |
} while (!result); | |
if (i != val) { | |
printf("error\n"); | |
break; | |
} else { | |
sum += i; | |
} | |
} | |
printf("sum %lld\n", sum); | |
} | |
int main(void) { | |
pthread_t tid; | |
Queue<int> queue; | |
pthread_create(&tid, NULL, producer, &queue); | |
consumer(&queue); | |
pthread_join(tid, NULL); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment