linux c 字符串环形buf (二)

avatar
作者
猴君
阅读量:0

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>

int debug = 1;

pthread_mutex_t prod_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t prod_cond = PTHREAD_COND_INITIALIZER;

pthread_mutex_t cons_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cons_cond = PTHREAD_COND_INITIALIZER;

// Define the ring buffer structure
typedef struct {
    char *buffer;
    size_t capacity;
    size_t read_pos;
    size_t write_pos;
    char full;
    char empty;
    pthread_mutex_t lock;
} StringRingBuffer;

StringRingBuffer rb;

// Initialize the ring buffer
void init_string_ring_buffer(StringRingBuffer *rb, size_t capacity) {
    rb->buffer = malloc(capacity);
    if (rb->buffer == NULL) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    rb->capacity = capacity;
    rb->read_pos = 0;
    rb->write_pos = 0;
    rb->full = 0;
    rb->empty = 1;
    pthread_mutex_init(&rb->lock, NULL);
}

// Destructor for the ring buffer
void destroy_string_ring_buffer(StringRingBuffer *rb) {
    free(rb->buffer);
    pthread_mutex_destroy(&rb->lock);
}

// Write data to the ring buffer
ssize_t write_to_string_ring_buffer(StringRingBuffer *rb, const char *data, size_t len) 
{
    ssize_t written = 0;
    size_t write_pos;
    size_t read_pos;

    size_t space_before_wrap;
    size_t available_space;

    if (len == 0)
        return -1;

    pthread_mutex_lock(&rb->lock);
    if (rb->full == 1)
    {
        //is full
        goto write_end;
    }

    //printf("==> write_to_string\n");

    write_pos = rb->write_pos;
    read_pos = rb->read_pos;

    if (write_pos < read_pos)
    {
        available_space = read_pos - write_pos;    

        // real len
        len = len < available_space ? len : available_space;

        memcpy(rb->buffer + write_pos, data, len);
        rb->write_pos += len;
        written = len;
    }
    else if (write_pos >= read_pos)
    {
        available_space = rb->capacity - (write_pos - read_pos);

        // real len
        len = len < available_space ? len : available_space;

        space_before_wrap = rb->capacity - write_pos;
        
        if (len <= space_before_wrap)
        {
            memcpy(rb->buffer + write_pos, data, len);
            rb->write_pos += len;
            if(rb->write_pos > rb->capacity)
            {
                printf("error: in write:%lu rb->write_pos > rb->capacity =======================================\n", rb->write_pos );    
                exit(-1);
            }
            if (rb->write_pos >= rb->capacity) {
                rb->write_pos = 0;
            }
            written = len;
        }
        else
        {
            // Wrap around
            memcpy(rb->buffer + write_pos, data, space_before_wrap);
            memcpy(rb->buffer, data + space_before_wrap, len - space_before_wrap);
            rb->write_pos = len - space_before_wrap;
            written = len;
        }

    }

    if(debug)
        printf("[%lu]Wrote %ld bytes, write_pos:%ld read_pos:%ld\n", pthread_self() , written, rb->write_pos,  rb->read_pos);
    if (rb->write_pos == rb->read_pos)
    {
        rb->full = 1;
        if(debug)
            printf("[%lu]full  write_pos:%ld-%ld read_pos:%ld-%ld\n", pthread_self() , rb->write_pos,write_pos, rb->read_pos,read_pos);
    }


    //printf("<== write_to_string\n");

write_end:
    rb->empty = 0;
    pthread_mutex_unlock(&rb->lock);

    return written;
}

// Read data from the ring buffer
ssize_t read_from_string_ring_buffer(StringRingBuffer *rb, char *dest, size_t len) 
{
    ssize_t read_len = 0;
    size_t write_pos; 
    size_t read_pos;  

    size_t data_before_wrap;
    //size_t data_after_wrap;

    size_t available_data;

    if (len == 0)
        return -1;

    pthread_mutex_lock(&rb->lock);
    if (rb->empty == 1)
    {
        goto read_end;
    }
    //printf("==> read_from_string\n");
    
    write_pos = rb->write_pos;
    read_pos = rb->read_pos;

    if (write_pos <= read_pos)
    {
        available_data = rb->capacity - (read_pos - write_pos);
        if (len > available_data)
        {
            //not enough
            goto read_end;
        }

        data_before_wrap = rb->capacity - read_pos;
        if (len <= data_before_wrap)
        {
            memcpy(dest, rb->buffer + read_pos, len);
            rb->read_pos += len;
            if(rb->read_pos > rb->capacity)
            {
                printf("error: in read:%lu rb->read_pos > rb->capacity =======================================\n", rb->read_pos);    
                exit(-1);
            }

            if (rb->read_pos >= rb->capacity) {
                rb->read_pos = 0;
            }
            read_len = len;
        }
        else
        {
            memcpy(dest, rb->buffer + read_pos, data_before_wrap);
            memcpy(dest + data_before_wrap, rb->buffer, len - data_before_wrap);
            rb->read_pos = len - data_before_wrap;
            read_len = len;
        }
    }
    else if (write_pos > read_pos)
    {
        available_data = write_pos - read_pos;
        if (len > available_data)
        {
            //not enough
            goto read_end;
        }

        memcpy(dest, rb->buffer + read_pos, len);
        rb->read_pos += len;
        read_len = len;
    }

    if(debug)
        printf("[%lu]Read %ld bytes: '%s', write_pos:%ld read_pos:%ld\n",  pthread_self() , read_len, dest, rb->write_pos, rb->read_pos);
    if (rb->write_pos == rb->read_pos)
    {
        rb->empty = 1;
        if(debug)
            printf("[%lu]empty write_pos:%ld-%ld read_pos:%ld-%ld\n",   pthread_self(), rb->write_pos, write_pos, rb->read_pos, read_pos);
    }


    //printf("<== read_from_string\n");

read_end:
    rb->full = 0;

    pthread_mutex_unlock(&rb->lock);

    return read_len;
}


void *func_producer(void *arg)
{
    arg = arg;
    struct timespec tv;

    // Write some data
    ssize_t written;
    char test_str[] = "0123456789";
    tv.tv_sec = 1;
    while(1)
    {
        pthread_mutex_lock(&prod_mutex);
        pthread_cond_timedwait(&prod_cond, &prod_mutex, &tv);
        //pthread_cond_wait(&prod_cond, &prod_mutex);
        //sleep(1);
        while (1)
        {
            written = write_to_string_ring_buffer(&rb, test_str, strlen(test_str));
            if(written <= 0)
            {
                //pthread_cond_signal(&cons_cond);
                pthread_cond_broadcast(&cons_cond);
                break;
            }
            //printf("Wrote %ld bytes\n", written);
        }
        pthread_mutex_unlock(&prod_mutex);
    }

    return NULL;
}

void *func_consumer(void *arg)
{
    arg = arg;
    struct timespec tv;

    // Read the data back
    ssize_t read_len;
    char read_buf[20];

    tv.tv_sec = 1;

    while(1)
    {
        //sleep(1);
        pthread_mutex_lock(&cons_mutex);
        pthread_cond_timedwait(&cons_cond, &cons_mutex, &tv);
        //pthread_cond_wait(&cons_cond, &cons_mutex);
        while(1)
        {
            memset(read_buf, 0, sizeof(read_buf));
            read_len = read_from_string_ring_buffer(&rb, read_buf, 10);
            if(read_len <=0)
            {
                //pthread_cond_signal(&prod_cond);
                pthread_cond_broadcast(&prod_cond);
                //sleep(1);
                //printf("Read %ld bytes: '%s'\n", read_len, read_buf);
                break;
            }
            //printf("Read %ld bytes: '%s' out\n", read_len, read_buf);

        }
        pthread_mutex_unlock(&cons_mutex);
    }

    return NULL;
}

//gcc -g -O0 -std=c99 -Wall -Wextra -pedantic -pthread test.c -o string_ring_buffer

// Example usage
int main() {
    int i;
    pthread_t  t_prod[10];
    pthread_t  t_cons[10];


    init_string_ring_buffer(&rb, 25);  // Initialize the ring buffer with capacity 20


    for(i=0; i<5; i++)
    {
        pthread_create(&t_prod[i], NULL, func_producer, NULL);
        pthread_create(&t_cons[i], NULL, func_consumer, NULL);
    }
    // Clean up
    destroy_string_ring_buffer(&rb);

    for(i=0; i<5; i++)
    {
        pthread_join(t_prod[i], NULL);    
        pthread_join(t_cons[i], NULL);    
    }

    return 0;
}
 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!