C语言环形队列

#include <stdio.h>
#define Len 6
unsigned char Input_Buff[6] = {0}; //用户输入缓冲区
unsigned char Input_Num  = 0;      //输入队列数据字节数
unsigned char Output_Num = 0;      //从队列取出的数据字节数
struct Queue
{
    unsigned char  Buffer[Len]; 
    unsigned char* Head;
    unsigned char* Tail;
};
Queue Ring_Queue;
void Empty() { //清空队列
    Ring_Queue.Head = Ring_Queue.Buffer;//Buffer缓冲区数组
    Ring_Queue.Tail = Ring_Queue.Buffer;
}

void Write(unsigned char* pData, unsigned char Data_Len) {  //入队列
    for (unsigned char Data_Num = 0; Data_Num < Data_Len; Data_Num++) {
        Ring_Queue.Buffer[Ring_Queue.Tail - Ring_Queue.Buffer] = *pData;
        pData++; 
        Ring_Queue.Tail++; //尾指针指向写入数据的末端
        if (Ring_Queue.Tail == Ring_Queue.Buffer + Len) {
            Ring_Queue.Tail = Ring_Queue.Buffer;
        }
        if (Ring_Queue.Head == Ring_Queue.Tail) { //不覆盖旧数据
            return;
        }
        printf("\n\r");
    }
}


void Read(unsigned char Read_Len) { //从队列中取出
    unsigned char Result = 0;
    for (unsigned char Read_Num = 0; Read_Num < Read_Len; Read_Num++) {
        Result = *(Ring_Queue.Head); //头指针指向读出数据后队列中剩余数据的开头
        *(Ring_Queue.Head) = NULL;
        printf("%hhu\n\r", Result);
        Ring_Queue.Head++;
        if (Ring_Queue.Head == Ring_Queue.Buffer + Len) {
            Ring_Queue.Head = Ring_Queue.Buffer;
        }
    }
    printf("\n\r");
}
void Key_Input() {
    printf("输入数据:\n\r");
    for (unsigned char Scanf_Num = 0; Scanf_Num < 6; Scanf_Num++) {
        scanf_s(" %hhu", &Input_Buff[Scanf_Num]);  //注意%hhu前的空格
    }
    printf("输入长度:\n\r");
    scanf_s("%hhu", &Input_Num);
    printf("读取长度:\n\r");
    scanf_s("%hhu", &Output_Num);
}
int main() {
    Empty();
    while (1) {
        Key_Input();
        Write(Input_Buff, Input_Num);
        Read(Output_Num);
    }
    return 0;
}

验证效果 输入4个数字(这里必须输入六个数字后截取前四个,暂时没想到很好的解决办法),取出3个,再输入5个,全部取出,观察是否没有覆盖旧数据。

 可以看到第一次输入的1 2 3 4 ,取出的是1 2 3,此时队列中还剩4 ,写入 9 8 7 6 5 后,由于不覆盖旧数据,因此队列中应该是4 9 8 7 6 5,最终验证代码正确。

<think>嗯,用户想知道如何优化C语言实现的环形队列。首先,我得回忆一下环形队列的基本结构和常见的问题。环形队列通常用数组实现,通过头尾指针来管理数据的进出,避免数据的搬移,提高效率。不过,C语言本身不支持泛型,所以扩展性可能是个问题。 根据提供的引用,优化方法包括使用void指针和动态内存分配来实现泛型支持。这样队列可以处理不同类型的数据。比如引用[1]提到,将存储结构改为void*,并用element_size记录元素大小,这样插入和删除时用memcpy操作内存。这应该能解决类型限制的问题。 动态内存分配也很重要。初始化时根据element_size分配空间,如引用[2]中的初始化函数,虽然例子中是int类型,但可以改为使用malloc(element_size * size)来支持任意类型。但要注意内存释放,避免泄漏。 线程安全也是一个优化点。引用[4]讨论使用原子操作和CAS(Compare-And-Swap)来保证多线程环境下的数据一致性。比如在push和pop操作中使用原子变量,确保头尾指针的修改是原子的,避免竞态条件。不过,C11标准支持原子操作,可能需要包含<stdatomic.h>头文件。 然后,引用[5]提到判断队列空和满的解决方法。常用的方法是少用一个元素空间,这样当(rear + 1) % size == front时认为队列满,而rear == front为空。或者使用计数器记录元素数量,这样判断更直接,但需要维护计数器,可能增加开销。 另外,内存对齐可能影响性能。引用[1]提到,根据element_size调整内存对齐,比如对于4字节类型,按4字节对齐,这可以通过编译器指令如__attribute__((aligned(n)))来实现,提升访问速度。 错误处理机制也不能忽视。比如返回布尔值表示操作成功与否,或者设置错误码,让调用者能处理异常情况,如队列满时无法入队。 缓存优化方面,确保频繁访问的变量(如head和tail)放在同一缓存行,减少伪共享。但如果是多线程,可能需要将它们分开到不同缓存行,避免竞争。这可以通过填充字节或使用对齐指令实现。 总结一下,优化点包括泛型支持、动态内存、线程安全、空满判断、内存对齐、错误处理和缓存优化。每个方面都需要仔细考虑实现细节,比如使用void*和memcpy时要注意内存越界,原子操作的正确使用,以及如何高效管理内存。同时,测试不同情况下的性能,比如单线程和多线程环境,确保优化的有效性。</think>### C语言环形队列优化方法分步说明 环形队列优化需要从数据结构设计、内存管理和线程安全三个方面入手,以下是具体优化步骤: 1. **泛型支持优化** - 修改存储结构为`void*`指针,支持任意数据类型: ```c typedef struct { void *buffer; // 数据存储区 size_t element_size; // 单个元素字节数 size_t capacity; // 队列容量 size_t head; // 头指针 size_t tail; // 尾指针 } RingBuffer; ``` 通过`element_size`记录元素大小,插入时使用`memcpy`进行内存操作[^1] 2. **动态内存管理** - 初始化函数增加动态分配: ```c void init_ringbuffer(RingBuffer *rb, size_t element_size, size_t capacity) { rb->buffer = malloc(element_size * (capacity + 1)); // 多分配1个元素空间 rb->element_size = element_size; rb->capacity = capacity; rb->head = rb->tail = 0; } ``` 通过`capacity + 1`实现少用一个元素的空满判断法[^5] 3. **线程安全实现** - 使用C11原子操作保证并发安全: ```c #include <stdatomic.h> typedef struct { _Atomic size_t head; // 原子头指针 _Atomic size_t tail; // 原子尾指针 // ...其他成员 } AtomicRingBuffer; bool atomic_push(AtomicRingBuffer *rb, void *data) { size_t current_tail = atomic_load(&rb->tail); size_t next_tail = (current_tail + 1) % (rb->capacity + 1); if(next_tail == atomic_load(&rb->head)) return false; // 队列满 memcpy((char*)rb->buffer + current_tail * rb->element_size, data, rb->element_size); atomic_store(&rb->tail, next_tail); return true; } ``` 通过原子操作实现无锁队列,参考CAS机制优化[^4] 4. **空满判断优化** - 采用计数器替代指针比较: ```c typedef struct { // ...原有成员 size_t count; // 元素计数器 } CounterRingBuffer; bool is_full(CounterRingBuffer *rb) { return rb->count == rb->capacity; } ``` 避免计算`(tail+1)%capacity == head`的开销[^5] 5. **内存对齐优化** - 根据元素大小设置内存对齐: ```c struct aligned_buffer { void *buffer __attribute__((aligned(64))); // 64字节对齐 // ...其他成员 }; ``` 提升缓存行访问效率,特别是处理大型结构体时 6. **批量操作优化** - 实现批量入队/出队函数: ```c size_t batch_enqueue(RingBuffer *rb, void *data, size_t num) { size_t free_space = rb->capacity - (rb->tail - rb->head) % rb->capacity; size_t actual_num = min(num, free_space); size_t first_chunk = min(actual_num, rb->capacity - rb->tail); memcpy((char*)rb->buffer + rb->tail * rb->element_size, data, first_chunk * rb->element_size); if(actual_num > first_chunk) { memcpy(rb->buffer, (char*)data + first_chunk * rb->element_size, (actual_num - first_chunk) * rb->element_size); } rb->tail = (rb->tail + actual_num) % rb->capacity; return actual_num; } ``` 减少单元素操作的系统调用开销 7. **错误处理强化** - 增加错误码返回机制: ```c typedef enum { RB_SUCCESS = 0, RB_FULL, RB_EMPTY, RB_INVALID_PTR } RB_ErrorCode; RB_ErrorCode safe_enqueue(RingBuffer *rb, void *data) { if(!rb || !data) return RB_INVALID_PTR; if(is_full(rb)) return RB_FULL; // ...正常操作 return RB_SUCCESS; } ``` **性能测试建议**: 1. 对比单线程下不同实现方式的吞吐量 2. 测试多生产者-多消费者场景的线程安全性 3. 分析内存对齐对缓存命中率的影响 4. 测量批量操作相比单元素操作的性能提升
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值