大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
例子:
ringbuffer.c实现
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "ringbuffer.h"
void ringbuffer_init(struct ringbuffer *rb, uint8_t *pool, int16_t size)
{
if(rb == NULL)
{
return;
}
rb->read_mirror = rb->read_index = 0;
rb->write_mirror = rb->write_index = 0;
rb->buffer_ptr = pool;
rb->buffer_size = size;
pthread_mutex_init(&rb->mutex_lock,NULL);
return;
}
void ringbuffer_reset(struct ringbuffer *rb)
{
if(rb == NULL)
{
return;
}
rb->read_mirror = 0;
rb->read_index = 0;
rb->write_mirror = 0;
rb->write_index = 0;
return;
}
int16_t ringbuffer_put(struct ringbuffer *rb, const uint8_t *ptr, int16_t length)
{
if(rb == NULL || length == 0)
{
return 0;
}
int16_t size;
pthread_mutex_lock(&rb->mutex_lock);
size = ringbuffer_space_len(rb);
pthread_mutex_unlock(&rb->mutex_lock);
if(size == 0)
return 0;
if (size < length)
{
length = size;
}
if (rb->buffer_size - rb->write_index > length)
{
memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
rb->write_index += length;
return length;
}
memcpy(&rb->buffer_ptr[rb->write_index],&ptr[0],rb->buffer_size - rb->write_index);
memcpy(&rb->buffer_ptr[0],&ptr[rb->buffer_size - rb->write_index],length - (rb->buffer_size - rb->write_index));
pthread_mutex_lock(&rb->mutex_lock);
rb->write_mirror = ~rb->write_mirror;
rb->write_index = length - (rb->buffer_size - rb->write_index);
pthread_mutex_unlock(&rb->mutex_lock);
return length;
}
int16_t ringbuffer_get(struct ringbuffer *rb, uint8_t *ptr, int16_t length)
{
if(rb == NULL || length == 0)
{
return 0;
}
int16_t size;
pthread_mutex_lock(&rb->mutex_lock);
size = ringbuffer_data_len(rb);
pthread_mutex_unlock(&rb->mutex_lock);
if (size == 0) return 0;
if (size < length)
{
length = size;
}
if (rb->buffer_size - rb->read_index > length)
{
memcpy(ptr, &rb->buffer_ptr[rb->read_index], length);
rb->read_index += length;
return length;
}
memcpy(&ptr[0],&rb->buffer_ptr[rb->read_index],rb->buffer_size - rb->read_index);
memcpy(&ptr[rb->buffer_size - rb->read_index], &rb->buffer_ptr[0], length - (rb->buffer_size - rb->read_index));
pthread_mutex_lock(&rb->mutex_lock);
rb->read_mirror = ~rb->read_mirror;
rb->read_index = length - (rb->buffer_size - rb->read_index);
pthread_mutex_unlock(&rb->mutex_lock);
return length;
}
enum ringbuffer_state ringbuffer_status(struct ringbuffer *rb)
{
if (rb->read_index == rb->write_index)
{
if (rb->read_mirror == rb->write_mirror)
{
return RINGBUFFER_EMPTY;
}
else
{
return RINGBUFFER_FULL;
}
}
return RINGBUFFER_HALFFULL;
}
int16_t ringbuffer_data_len(struct ringbuffer *rb)
{
switch (ringbuffer_status(rb))
{
case RINGBUFFER_EMPTY:
return 0;
case RINGBUFFER_FULL:
return rb->buffer_size;
case RINGBUFFER_HALFFULL:
default:
if (rb->write_index > rb->read_index)
return rb->write_index - rb->read_index;
else
return rb->buffer_size - (rb->read_index - rb->write_index);
}
}
ringbuffer.h
#ifndef __RING_BUFFER__
#define __RING_BUFFER__
#include <stdint.h>
#include <stddef.h>
#include <pthread.h>
#include <unistd.h>
struct ringbuffer
{
uint8_t *buffer_ptr;
uint16_t read_mirror : 1;
uint16_t read_index : 15;
uint16_t write_mirror : 1;
uint16_t write_index : 15;
int16_t buffer_size;
pthread_mutex_t mutex_lock;
};
enum ringbuffer_state
{
RINGBUFFER_EMPTY,
RINGBUFFER_FULL,
RINGBUFFER_HALFFULL,
RINGBUFFER_INVALID,
};
void ringbuffer_init(struct ringbuffer *rb, uint8_t *pool, int16_t size);
void ringbuffer_reset(struct ringbuffer *rb);
int16_t ringbuffer_put(struct ringbuffer *rb, const uint8_t *ptr, int16_t length);
int16_t ringbuffer_get(struct ringbuffer *rb, uint8_t *ptr, int16_t length);
int16_t ringbuffer_data_len(struct ringbuffer *rb);
struct ringbuffer* ringbuffer_create(int16_t length);
void ringbuffer_destroy(struct ringbuffer *rb);
static inline int16_t ringbuffer_get_size(struct ringbuffer *rb)
{
return rb->buffer_size;
}
#define ringbuffer_space_len(rb) ((rb)->buffer_size - ringbuffer_data_len(rb))
#endif
main.c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include "ringbuffer.h"
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
struct ringbuffer *rb;
void *writer_thread(void *args)
{
uint8_t w = 0;
while(1)
{
/*pthread_mutex_lock(&mutex);*/
if(ringbuffer_put(rb, &w, 1) == 1)
w ++;
/*pthread_mutex_unlock(&mutex);*/
}
return NULL;
}
void *reader_thread(void *args)
{
uint8_t r;
while(1)
{
/*pthread_mutex_lock(&mutex);*/
if (ringbuffer_get(rb, &r, 1) == 1)
printf("---%x---\n", r);
/*pthread_mutex_unlock(&mutex);*/
}
return NULL;
}
int main(void)
{
unsigned int rc;
#if 1
uint8_t *buffer = (uint8_t *)malloc(1024 + sizeof(struct ringbuffer) + 16);
if(buffer == NULL) return -1;
if((unsigned long)buffer & 7 != 0)
{
printf("%s line %d not aligned.\n", __func__, __LINE__);
return -1;
}
rb=(struct ringbuffer *)buffer;
if(rb == NULL) return -1;
ringbuffer_init(rb, buffer + sizeof(struct ringbuffer), 1024);
printf("buffer = %p, sizeof(rb) = %ld.\n", buffer, sizeof(struct ringbuffer));
#else
static struct ringbuffer rbb;
uint8_t *buffer = (uint8_t *)malloc(1024);
if(buffer == NULL) return -1;
rb = &rbb;
memset(rb, 0x00,sizeof(struct ringbuffer));
memset(buffer, 0x00,1024);
ringbuffer_init(rb, buffer, 1024);
#endif
pthread_t writer;
rc = pthread_create(&writer, NULL, writer_thread, NULL);
if (rc)
{
printf("ERROR; return code is %d\n", rc);
return EXIT_FAILURE;
}
pthread_t reader;
rc = pthread_create(&reader, NULL, reader_thread, NULL);
if (rc)
{
printf("ERROR; return code is %d\n", rc);
return EXIT_FAILURE;
}
pthread_join(reader, NULL);
pthread_join(writer, NULL);
return EXIT_SUCCESS;
}
运行无问题,但是当把ringbuffer.c中的锁保护去掉后:
执行出错:
用GDB观察一下:
length竟然是负值.
所以源头是:
测试并计算并非原子的,所以这里肯定有问题,需要加锁保护,比如下图
在判断的时候write > read, 比如147行,但是当计算的时候,由于write是独立的线程,它已经将write递增并回绕到56.而且read由于在本线程,仍然保留了706,所以已经不符合判断时候的逻辑write>read.
但是仍然按照错误的逻辑计算,所得得到了负值.
解决的办法就是将判断和计算上锁原子化.
结束!
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/197545.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...