程式語言 - GNU - C/C++ - Ring Buffer



main.c

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/ioctl.h>

#define QUEUE_SIZE  1024

typedef struct {
    int size;
    int read;
    int write;
    uint8_t *buffer;
    pthread_mutex_t lock;
} queue_t;

static queue_t queue = {0};

static void queue_init(queue_t *q, size_t s)
{
    q->buffer = (uint8_t *)malloc(s);
    q->size = s;
    q->read = q->write = 0;
    pthread_mutex_init(&q->lock, NULL);
}

static void queue_destroy(queue_t *q)
{
    if (q->buffer) {
        free(q->buffer);
    }
    pthread_mutex_destroy(&q->lock);
}

static int queue_size_for_read(queue_t *q)
{
    if (q->read == q->write) {
        return 0;
    }
    else if(q->read < q->write) {
        return q->write - q->read;
    }
    return (QUEUE_SIZE - q->read) + q->write;
}

static int queue_size_for_write(queue_t *q)
{
    if (q->write == q->read) {
        return QUEUE_SIZE;
    }
    else if (q->write < q->read) {
        return q->read - q->write;
    }
    return (QUEUE_SIZE - q->write) + q->read;
}

static int queue_put(queue_t *q, uint8_t *buffer, size_t size)
{
    int r = 0, tmp = 0, avai = 0;

    pthread_mutex_lock(&q->lock);
    avai = queue_size_for_write(q);
    if (size > avai) {
        size = avai;
    }
    r = size;

    if (size > 0) {
        if ((q->write >= q->read) && ((q->write + size) > QUEUE_SIZE)) {
            tmp = QUEUE_SIZE - q->write;
            size-= tmp;
            memcpy(&q->buffer[q->write], buffer, tmp);
            memcpy(q->buffer, &buffer[tmp], size);
            q->write = size;
        }
        else {
            memcpy(&q->buffer[q->write], buffer, size);
            q->write += size;
        }
    }
    pthread_mutex_unlock(&q->lock);
    return r;
}

static size_t queue_get(queue_t *q, uint8_t *buffer, size_t max)
{
    int r = 0, tmp = 0, avai = 0, size = max;

    pthread_mutex_lock(&q->lock);
    avai = queue_size_for_read(q);
    if (size > avai) {
        size = avai;
    }
    r = size;

    if (size > 0) {
        if ((q->read > q->write) && (q->read + size) > QUEUE_SIZE) {
            tmp = QUEUE_SIZE - q->read;
            size-= tmp;
            memcpy(buffer, &q->buffer[q->read], tmp);
            memcpy(&buffer[tmp], q->buffer, size);
            q->read = size;
        }
        else {
            memcpy(buffer, &q->buffer[q->read], size);
            q->read+= size;
        }
    }
    pthread_mutex_unlock(&q->lock);
    return r;
}

int main(int argc, char **argv)
{
    char buf[32] = {0};
    int ret = 0, cc = 0;

    queue_init(&queue, (size_t)QUEUE_SIZE);
    if (queue.buffer == NULL) {
        return -1;
    }
    memset(queue.buffer, 0, QUEUE_SIZE);

    buf[0] = 0x00;
    buf[1] = 0x11;
    queue_put(&queue, buf, 2);
    
    buf[0] = 0x22;
    buf[1] = 0x33;
    buf[2] = 0x44;
    queue_put(&queue, buf, 3);
    
    ret = queue_get(&queue, buf, sizeof(buf));
    printf("ret: %d\n", ret);
    for (cc=0; cc<ret; cc++) {
        printf("0x%02x, ", buf[cc]);
    }
    printf("\n");

    queue_destroy(&queue);
    return 0;
}

編譯、執行

$ gcc main.c -o test
$ ./test
    ret: 5
    0x00, 0x11, 0x22, 0x33, 0x44,