这是C语言手写高性能并发容器系列第一篇。由于在微软实习的任务一个月就做完了。故自己找点事情做。
没啥难的。只是用 C 自己写了大家都懂的一些机制。
自动扩容,支持并发访问。提供了如下的操作方法。
#pragma once
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#define INIT_SIZE 4
typedef struct con_vector {
void** data;
size_t cap;
size_t tail;
pthread_spinlock_t lock;
}con_vector;
// constructor
con_vector* create_vector() {
con_vector* ret = malloc(sizeof(con_vector));
ret->cap = (1 << INIT_SIZE);
ret->data = malloc(sizeof(void*) * ret->cap);
ret->tail = 0;
pthread_spin_init(&ret->lock, PTHREAD_PROCESS_PRIVATE);
return ret;
}
// auto-expansion, DO NOT CALL MANNUALLY
void resize(con_vector* s) {
s->cap <<= 1;
void** old = s->data;
s->data = malloc(sizeof(void*) * s->cap);
memcpy(s->data, old, sizeof(void*) * s->tail);
free(old);
}
// push an item to the back
void push_back(con_vector* s, void* val) {
pthread_spin_lock(&s->lock);
if(s->tail == s->cap) {
resize(s);
}
s->data[s->tail ++] = val;
pthread_spin_unlock(&s->lock);
}
// pop and return the last item, if data is empty, return NULL
void* pop_back(con_vector* s) {
pthread_spin_lock(&s->lock);
if(s->tail == 0) {
pthread_spin_unlock(&s->lock);
return NULL;
}
void* ret = s->data[-- s->tail];
pthread_spin_unlock(&s->lock);
return ret;
}
// get the value of vector[i], reuturn NULL if i is out or range
void* get(con_vector* s, size_t i) {
pthread_spin_lock(&s->lock);
if(i < 0 || i >= s->tail) {
pthread_spin_unlock(&s->lock);
return NULL;
}
void* ret = s->data[i];
pthread_spin_unlock(&s->lock);
return ret;
}
// set the value of vector[i], return false if i is out of range
bool set(con_vector* s, size_t i, void* val) {
pthread_spin_lock(&s->lock);
if(i < 0 || i >= s->tail) {
pthread_spin_unlock(&s->lock);
return false;
}
s->data[i] = val;
pthread_spin_unlock(&s->lock);
return true;
}
// return the size of the vector
size_t size(con_vector* s) {
return s->tail - 1;
}
// quicksort
void sort(con_vector*s, void* cmp) {
pthread_spin_lock(&s->lock);
qsort(s->data, s->tail, sizeof(void*), cmp);
pthread_spin_unlock(&s->lock);
}
#pragma once
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#define INIT_SIZE 4
typedef struct con_queue {
void** data;
size_t cap;
size_t head;
size_t tail;
pthread_spinlock_t lock;
}con_queue;
// constructor
con_queue* create_queue() {
con_queue* ret = malloc(sizeof(con_queue));
ret->cap = (1 << INIT_SIZE) - 1;
ret->data = malloc(sizeof(void*) * (ret->cap + 1));
ret->head = 0;
ret->tail = 0;
pthread_spin_init(&ret->lock, PTHREAD_PROCESS_PRIVATE);
return ret;
}
// auto-expansion, DO NOT CALL MANNUALLY
void resize(con_queue* s) {
s->cap = (s->cap << 1) | 1;
void** old = s->data;
s->data = malloc(sizeof(void*) * (s->cap + 1));
if(s->head <= s->tail) {
memcpy(s->data, &old[s->head], sizeof(void*) * (s->tail - s->head));
s->tail -= s->head;
} else {
size_t fr = (s->cap >> 1) + 1 - s->head;
memcpy(s->data, &old[s->head], sizeof(void*) * fr);
memcpy(&s->data[fr], old, sizeof(void*) * s->tail);
s->tail += fr;
}
s->head = 0;
free(old);
}
// push an item to the back
void push(con_queue* s, void* val) {
pthread_spin_lock(&s->lock);
size_t nxt = (s->tail + 1) & s->cap;
if(nxt == s->head) {
resize(s);
nxt = s->tail + 1;
}
s->data[s->tail] = val;
s->tail = nxt;
pthread_spin_unlock(&s->lock);
}
// pop and return an item from the front, return NULL if queue is empty
void* pop(con_queue* s) {
pthread_spin_lock(&s->lock);
if(s->tail == s->head) {
pthread_spin_unlock(&s->lock);
return NULL;
}
void* ret = s->data[s->head];
s->head = (s->head + 1) & s->cap;
pthread_spin_unlock(&s->lock);
return ret;
}
// return the item from the front, return NULL if queue is empty
void* top(con_queue* s) {
pthread_spin_lock(&s->lock);
if(s->head == s->tail) {
pthread_spin_unlock(&s->lock);
return NULL;
}
void* ret = s->data[s->head];
pthread_spin_unlock(&s->lock);
return ret;
}
// return the size of the queue
size_t size(con_queue* s) {
pthread_spin_lock(&s->lock);
if(s->head <= s->tail) {
pthread_spin_unlock(&s->lock);
return s->tail - s->head;
} else {
pthread_spin_unlock(&s->lock);
return s->tail + s->cap + 1 - s->head;
}
}