문제

나를 위해 필요가 있는 고정 크기의(선택할 수 있는 실행 시간을 만들 때,그것을 컴파일되지 시간)원형 버퍼에 저장할 수 있는 객체의 모든 유형 및 그야 높은 성능을 제공합니다.지가 있다고 생각하지 않을 것입원 경쟁 문제가 있지만,그것은에서는 멀티태스킹을 포함 된 환경,그것의 협력을 하므로 작업 자체를 관리할 수 있습니다.

내 초기 생각이 있었을 저장소 간단한 구조체를 버퍼에 있는 것을 포함하는 형식(간단한 열거/정의하는)그리고 공허 포인터를 탑재하지만 저는 이를 가능한 한 빨리 그래서 나는 열기를 제안을 포함하는 우회합니다.

실제로 나는 행복한을 우회하는 표준 라이브러리를 위한 원 속에서 무엇을 나는 본 적이의 코드,그것은 크게 최적화된 CPU:다음과 같이 컴파일된 C 코드 같은 것들에 대한 strcpy() 과 같은 없는 손으로 코딩 어셈블리입니다.

코드는 아이디어를 주시면 감사하겠습니다.는 데 필요한 작업은:

  • 버퍼를 작성과 특정한 크기입니다.
  • 꼬리에 넣어.
  • 에서 얻을 머리에 있습니다.
  • 반환하는 계산합니다.
  • 삭제 버퍼입니다.
도움이 되었습니까?

해결책

할 수 있습니 열거의 형태이 필요한 시간에 코드까지 버퍼,또는 당신이 필요할 수 있는 추가 유형에서 실행을 통해 시간 동적니다.전자의 경우,다음 내용은 버퍼로 힙 할당 배의 구조체 n,각 구조은 두 가지 분야로 구성되어 있습니다:enum 태그 데이터를 식별하는 형식,그리고 동맹의 모든 데이터 유형이 있습니다.당신은 무엇을 잃의 관점에서 추가 저장을위한 작은 요소들이,당신은 당신의 관점에서 처리하지 않으로 할당 및 할당 해제 결과 메모리다.다음은 필요한 추적을 유지하의 시작과 끝을 지수를 정의하는 머리와 꼬리 요소의 버퍼,그리고 확인 컴퓨팅 모 n 때 증가/감소시키는 인덱스.

다른 팁

가장 간단한 솔루션을 추적하는 항목의 크기와 항목의 수,그리고 버퍼의 바이트 수:

typedef struct circular_buffer
{
    void *buffer;     // data buffer
    void *buffer_end; // end of data buffer
    size_t capacity;  // maximum number of items in the buffer
    size_t count;     // number of items in the buffer
    size_t sz;        // size of each item in the buffer
    void *head;       // pointer to head
    void *tail;       // pointer to tail
} circular_buffer;

void cb_init(circular_buffer *cb, size_t capacity, size_t sz)
{
    cb->buffer = malloc(capacity * sz);
    if(cb->buffer == NULL)
        // handle error
    cb->buffer_end = (char *)cb->buffer + capacity * sz;
    cb->capacity = capacity;
    cb->count = 0;
    cb->sz = sz;
    cb->head = cb->buffer;
    cb->tail = cb->buffer;
}

void cb_free(circular_buffer *cb)
{
    free(cb->buffer);
    // clear out other fields too, just to be safe
}

void cb_push_back(circular_buffer *cb, const void *item)
{
    if(cb->count == cb->capacity){
        // handle error
    }
    memcpy(cb->head, item, cb->sz);
    cb->head = (char*)cb->head + cb->sz;
    if(cb->head == cb->buffer_end)
        cb->head = cb->buffer;
    cb->count++;
}

void cb_pop_front(circular_buffer *cb, void *item)
{
    if(cb->count == 0){
        // handle error
    }
    memcpy(item, cb->tail, cb->sz);
    cb->tail = (char*)cb->tail + cb->sz;
    if(cb->tail == cb->buffer_end)
        cb->tail = cb->buffer;
    cb->count--;
}
// Note power of two buffer size
#define kNumPointsInMyBuffer 1024 

typedef struct _ringBuffer {
    UInt32 currentIndex;
    UInt32 sizeOfBuffer;
    double data[kNumPointsInMyBuffer];
} ringBuffer;

// Initialize the ring buffer
ringBuffer *myRingBuffer = (ringBuffer *)calloc(1, sizeof(ringBuffer));
myRingBuffer->sizeOfBuffer = kNumPointsInMyBuffer;
myRingBuffer->currentIndex = 0;

// A little function to write into the buffer
// N.B. First argument of writeIntoBuffer() just happens to have the
// same as the one calloc'ed above. It will only point to the same
// space in memory if the calloc'ed pointer is passed to
// writeIntoBuffer() as an arg when the function is called. Consider
// using another name for clarity
void writeIntoBuffer(ringBuffer *myRingBuffer, double *myData, int numsamples) {
    // -1 for our binary modulo in a moment
    int buffLen = myRingBuffer->sizeOfBuffer - 1;
    int lastWrittenSample = myRingBuffer->currentIndex;

    int idx;
    for (int i=0; i < numsamples; ++i) {
        // modulo will automagically wrap around our index
        idx = (i + lastWrittenSample) & buffLen; 
        myRingBuffer->data[idx] = myData[i];
    }

    // Update the current index of our ring buffer.
    myRingBuffer->currentIndex += numsamples;
    myRingBuffer->currentIndex &= myRingBuffer->sizeOfBuffer - 1;
}

으로 링 버퍼의 길이는 두 개의 전원,믿을 수 없을만큼 빨리 바이너리"&"작업이 포장의 주위에 당신의 색인을 위해 당신입니다.내 응용 프로그램,나를 표시하 세그먼트의 오디오를 사용자에서 링 버퍼의 오디오에서 획득한 마이크.

나는 항상 있는지 확인하는 최대 금액의 오디오를 표시할 수 있는 화면에서는 보다 훨씬 적은 크기의 링 버퍼입니다.그렇지 않으면 당신은 수 있습 읽기와 쓰기에서 같은 덩어리.이것이 당신이 이상한 표시입니다.

먼저를 즐길 수 있습니다.당신이 필요하지 않는 모듈로 연산하여 포장 버퍼를 사용하는 경우 비트 수를 보유하 머리&꼬리"포인터",크기를 그들을 그렇게 그들은 완벽하게 동기화.IE:4096 으로 채워진 12-bit unsigned int0 는 모든 자체적으로 괴롭히지에서는 어떤 방법입니다.모듈을 제거하는 산수,심지어 힘의 2,두 속도-거의 정확합니다.

10 백만 반복의 충전 및 배출 4096 버퍼의 모든 데이터의 유형 요소 52 초에 나의 3 세대 i7Dell XPS8500Visual Studio 를 사용하여 2010 년의 C++컴파일러 기본값으로 인라인,그리고 1/8192nd 의하는 서비스는 자료.

나 RX 다시 쓰기 테스트에서 루프 main()그래서 그들은 더 이상 흐름을 제어하는,그리고해야에 의해 제어되는 반환 값을 나타내는 버퍼가 가득하거나 비어 있으며,승무원 휴식;문입니다.IE:충전제 및 배수해야 할 수 있 bang 없이 서로에 대하여 손상이나 불안정하게 만듭니다.어떤 시점에서 나는 멀티-스레드 이 코드는,그러자 하는 행동을 것이 매우 중요합니다.

이 QUEUE_DESC(큐 descriptor)와 초기화 함수에서는 모든 버퍼에 이 코드를 수의 힘 2.위의 방식이 작동하지 않습니다.하는 동안,주제에 참고 QUEUE_DESC 지 않 하드 코딩,그것은 매니페스트 일(#define BITS_ELE_KNT)에 대한 그것의 건설입니다.(나는 가정원의 2 는 여기에 충분한 유연성)

을 버퍼 크기는 실행시 선택할 수 있는,나 다른 방법(여기에 표시되지 않),그리고 정착에 사용하 USHRTs 위해 머리,꼬리,EleKnt 를 관리할 수 있 FIFO buffer[USHRT].을 방지하 모듈산 내가 만들어진 마스크를&&으로 머리,꼬리지만,는 마스크로 밝혀(EleKnt-1),그래서 그냥 사용합니다.사용 USHRTS 대신 비트의 수가 증가능~15%에 조용 기계입니다.Intel CPU 코어가 항상보다 빠르게 자신의 버스,그래서 바쁜,공동 기계,패킹의 데이터 구조를 얻을 당신이 로드되어 실행하의 경쟁,스레드입니다.Trade-offs.

참고 실제 저장소를 버퍼에 할당된 힙 calloc(),그리고 포인터에서의 기본 구조체,그래서 구조체 및 이 포인터는 정확히 동일한 주소입니다.IE;no offset 필요한 추가하는 구조체 주소를 등록합니다.

에는 동정맥,모든 변수의 교환으로 서비스를 버퍼에 물리적으로 인접한 버퍼,바로 같은 구조체,그렇게 컴파일러를 만들 수 있는 아름다운 어셈블리 언어입니다.당신을 죽일 수 있는 인라인 최적화는 모든 어셈블리하기 때문에,그렇지 않으면 그것을 얻으로 분쇄 oblivion.

을 지원하는 다형성의 모든 데이터 유형에 사용했 memcpy 를()는 대신 과제입니다.해야 하는 경우에만 지원하는 유연성을 하나의 랜덤변수 유형별로는 컴파일,다음 이 코드를 완벽하게 작동합니다.

에 대한 다형성,당신은 단지 유형을 알고 있을 필요가 있고 그것의 저장 요구 사항입니다.이 DATA_DESC 의 배열을 설명하는 방법을 제공합 추적의 각각의 기준어에 QUEUE_DESC.pBuffer 그래서 그것을 검색할 수 있습니다.나는 단지 충분히 할당 pBuffer 메모리 모든 요소의 가장 큰 데이터의 유형,그러나 얼마나 추적의 저장은 주어진 데이터가에서 실제로 사용하는 DATA_DESC.dBytes.대안을 재발견한 힙 관리자입니다.

이 QUEUE_DESC 의 비*pBuffer 것 병렬 동반자열 추적을 유지하는 데이터의 형식 및 크기는 동안,자료의 저장소 위치에서 pBuffer 남아 있을 것입만으로는 지금이다.새로운 멤버가 뭔가 될 것 같은 DATA_DESC*pDataDesc,또는,아마,DATA_DESC DataDesc[2^BITS_ELE_KNT]을 찾을 수 있다면 이길 수 있는 방법을 컴파일러로 제출과 같은 앞으로 참조.Calloc()항상 더 유연에서 이러한 상황입니다.

당신은 여전히 memcpy 를()에 Q_Put(),Q_Get 지만,바이트 수를 실제로 복사에 의해 결정됩 DATA_DESC.dBytes,지 QUEUE_DESC.EleBytes.요소들은 잠재적으로의 모든 다른 종류와 크기 위해 주어진 넣어 또는 얻을.

이 코드를 만족하는 속도 및 버퍼 크기를 요구 사항을 만들 수 있는 요구사항을 충족하기 위해에 대한 6 개의 다른 데이터 유형이 있습니다.내가 남아 많은 테스트 설비의 형태로,printf()문을,그래서 당신은 자신을 만족시킬 수 있습(또는)그는 코드가 제대로 작동합니다.난수를 생성하는 코드를 작동한 임의의 머리/꼬리 콤보입니다.

enter code here
// Queue_Small.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdio.h>
#include <time.h>
#include <limits.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <math.h>

#define UCHAR unsigned char
#define ULONG unsigned long
#define USHRT unsigned short
#define dbl   double
/* Queue structure */
#define QUEUE_FULL_FLAG 1
#define QUEUE_EMPTY_FLAG -1
#define QUEUE_OK 0
//  
#define BITS_ELE_KNT    12  //12 bits will create 4.096 elements numbered 0-4095
//
//typedef struct    {
//  USHRT dBytes:8;     //amount of QUEUE_DESC.EleBytes storage used by datatype
//  USHRT dType :3; //supports 8 possible data types (0-7)
//  USHRT dFoo  :5; //unused bits of the unsigned short host's storage
// }    DATA_DESC;
//  This descriptor gives a home to all the housekeeping variables
typedef struct  {
    UCHAR   *pBuffer;   //  pointer to storage, 16 to 4096 elements
    ULONG Tail  :BITS_ELE_KNT;  //  # elements, with range of 0-4095
    ULONG Head  :BITS_ELE_KNT;  //  # elements, with range of 0-4095
    ULONG EleBytes  :8;     //  sizeof(elements) with range of 0-256 bytes
    // some unused bits will be left over if BITS_ELE_KNT < 12
    USHRT EleKnt    :BITS_ELE_KNT +1;// 1 extra bit for # elements (1-4096)
    //USHRT Flags   :(8*sizeof(USHRT) - BITS_ELE_KNT +1);   //  flags you can use
    USHRT   IsFull  :1;     // queue is full
    USHRT   IsEmpty :1;     // queue is empty
    USHRT   Unused  :1;     // 16th bit of USHRT
}   QUEUE_DESC;

//  ---------------------------------------------------------------------------
//  Function prototypes
QUEUE_DESC *Q_Init(QUEUE_DESC *Q, int BitsForEleKnt, int DataTypeSz);
int Q_Put(QUEUE_DESC *Q, UCHAR *pNew);
int Q_Get(UCHAR *pOld, QUEUE_DESC *Q);
//  ---------------------------------------------------------------------------
QUEUE_DESC *Q_Init(QUEUE_DESC *Q, int BitsForEleKnt, int DataTypeSz)    {
    memset((void *)Q, 0, sizeof(QUEUE_DESC));//init flags and bit integers to zero
    //select buffer size from powers of 2 to receive modulo 
    //                arithmetic benefit of bit uints overflowing
    Q->EleKnt   =   (USHRT)pow(2.0, BitsForEleKnt);
    Q->EleBytes =   DataTypeSz; // how much storage for each element?
    //  Randomly generated head, tail a test fixture only. 
    //      Demonstrates that the queue can be entered at a random point 
    //      and still perform properly. Normally zero
    srand(unsigned(time(NULL)));    // seed random number generator with current time
    Q->Head = Q->Tail = rand(); // supposed to be set to zero here, or by memset
    Q->Head = Q->Tail = 0;
    //  allocate queue's storage
    if(NULL == (Q->pBuffer = (UCHAR *)calloc(Q->EleKnt, Q->EleBytes)))  {
        return NULL;
    }   else    {
        return Q;
    }
}
//  ---------------------------------------------------------------------------
int Q_Put(QUEUE_DESC *Q, UCHAR *pNew)   
{
    memcpy(Q->pBuffer + (Q->Tail * Q->EleBytes), pNew, Q->EleBytes);
    if(Q->Tail == (Q->Head + Q->EleKnt)) {
        //  Q->IsFull = 1;
        Q->Tail += 1;   
        return QUEUE_FULL_FLAG; //  queue is full
    }
    Q->Tail += 1;   //  the unsigned bit int MUST wrap around, just like modulo
    return QUEUE_OK; // No errors
}
//  ---------------------------------------------------------------------------
int Q_Get(UCHAR *pOld, QUEUE_DESC *Q)   
{
    memcpy(pOld, Q->pBuffer + (Q->Head * Q->EleBytes), Q->EleBytes);
    Q->Head += 1;   //  the bit int MUST wrap around, just like modulo

    if(Q->Head == Q->Tail)      {
        //  Q->IsEmpty = 1;
        return QUEUE_EMPTY_FLAG; // queue Empty - nothing to get
    }
    return QUEUE_OK; // No errors
}
//
//  ---------------------------------------------------------------------------
int _tmain(int argc, _TCHAR* argv[])    {
//  constrain buffer size to some power of 2 to force faux modulo arithmetic
    int LoopKnt = 1000000;  //  for benchmarking purposes only
    int k, i=0, Qview=0;
    time_t start;
    QUEUE_DESC Queue, *Q;
    if(NULL == (Q = Q_Init(&Queue, BITS_ELE_KNT, sizeof(int)))) {
        printf("\nProgram failed to initialize. Aborting.\n\n");
        return 0;
    }

    start = clock();
    for(k=0; k<LoopKnt; k++)    {
        //printf("\n\n Fill'er up please...\n");
        //Q->Head = Q->Tail = rand();
        for(i=1; i<= Q->EleKnt; i++)    {
            Qview = i*i;
            if(QUEUE_FULL_FLAG == Q_Put(Q, (UCHAR *)&Qview))    {
                //printf("\nQueue is full at %i \n", i);
                //printf("\nQueue value of %i should be %i squared", Qview, i);
                break;
            }
            //printf("\nQueue value of %i should be %i squared", Qview, i);
        }
        //  Get data from queue until completely drained (empty)
        //
        //printf("\n\n Step into the lab, and see what's on the slab... \n");
        Qview = 0;
        for(i=1; i; i++)    {
            if(QUEUE_EMPTY_FLAG == Q_Get((UCHAR *)&Qview, Q))   {
                //printf("\nQueue value of %i should be %i squared", Qview, i);
                //printf("\nQueue is empty at %i", i);
                break;
            }
            //printf("\nQueue value of %i should be %i squared", Qview, i);
        }
        //printf("\nQueue head value is %i, tail is %i\n", Q->Head, Q->Tail);
    }
    printf("\nQueue time was %5.3f to fill & drain %i element queue  %i times \n", 
                     (dbl)(clock()-start)/(dbl)CLOCKS_PER_SEC,Q->EleKnt, LoopKnt);
    printf("\nQueue head value is %i, tail is %i\n", Q->Head, Q->Tail);
    getchar();
    return 0;
}

여기에는 간단한 솔루션에서는 C가정 인터럽트가 꺼져 있는 각 기능입니다.형성이 없&건 단지 일반적인 의미입니다.


#define BUFSIZE 128
char buf[BUFSIZE];
char *pIn, *pOut, *pEnd;
char full;

// init
void buf_init()
{
    pIn = pOut = buf;       // init to any slot in buffer
    pEnd = &buf[BUFSIZE];   // past last valid slot in buffer
    full = 0;               // buffer is empty
}

// add char 'c' to buffer
int buf_put(char c)
{
    if (pIn == pOut  &&  full)
        return 0;           // buffer overrun

    *pIn++ = c;             // insert c into buffer
    if (pIn >= pEnd)        // end of circular buffer?
        pIn = buf;          // wrap around

    if (pIn == pOut)        // did we run into the output ptr?
        full = 1;           // can't add any more data into buffer
    return 1;               // all OK
}

// get a char from circular buffer
int buf_get(char *pc)
{
    if (pIn == pOut  &&  !full)
        return 0;           // buffer empty  FAIL

    *pc = *pOut++;              // pick up next char to be returned
    if (pOut >= pEnd)       // end of circular buffer?
        pOut = buf;         // wrap around

    full = 0;               // there is at least 1 slot
    return 1;               // *pc has the data to be returned
}

간단한 구현으로 구성될 수 있습니다:

  • 버퍼,구현으로 배열의 크기 n,의 어떤 종류를 필요
  • 읽기 또는 포인터를 인덱스(어느 쪽이 더 효율적으로 프로세서)
  • 쓰 포인터 또는 인덱스
  • 카운터를 나타내는 얼마나 많은 데이터 버퍼(에서 파생 가능한 읽고 쓰는 포인터,하지만 빠른 트랙 그것은 별도)

때마다 당신이 쓰는 데이터는,당신은 사전에 작성 포인터를 증가 카운터입니다.을 읽을 때 당신은 데이터를 증가 포인터를 읽고 감소시킵니다.는 경우 포인터를 하나에 도달하는 n 으로 설정합니다.

당신은 쓸 수 없는 경우 counter=n.을 읽을 수 없는 경우 counter=0.

C 스타일 간단한 링 버퍼를 위해 정수입니다.첫 번째 사용 init 사용하여 넣어서 얻을.면 버퍼에 데이터가 포함되어 있지 않습니다 그것은 returns"0"zero.

//=====================================
// ring buffer address based
//=====================================
#define cRingBufCount   512
int     sRingBuf[cRingBufCount];    // Ring Buffer
int     sRingBufPut;                // Input index address
int     sRingBufGet;                // Output index address
Bool    sRingOverWrite;

void    GetRingBufCount(void)
{
int     r;
`       r= sRingBufPut - sRingBufGet;
        if ( r < cRingBufCount ) r+= cRingBufCount;
        return r; 
}

void    InitRingBuffer(void)
{
        sRingBufPut= 0;
        sRingBufGet= 0;
}       

void    PutRingBuffer(int d)
{
        sRingBuffer[sRingBufPut]= d;
        if (sRingBufPut==sRingBufGet)// both address are like ziro
        {
            sRingBufPut= IncRingBufferPointer(sRingBufPut);
            sRingBufGet= IncRingBufferPointer(sRingBufGet);
        }
        else //Put over write a data
        {
            sRingBufPut= IncRingBufferPointer(sRingBufPut);
            if (sRingBufPut==sRingBufGet)
            {
                sRingOverWrite= Ture;
                sRingBufGet= IncRingBufferPointer(sRingBufGet);
            }
        }
}

int     GetRingBuffer(void)
{
int     r;
        if (sRingBufGet==sRingBufPut) return 0;
        r= sRingBuf[sRingBufGet];
        sRingBufGet= IncRingBufferPointer(sRingBufGet);
        sRingOverWrite=False;
        return r;
}

int     IncRingBufferPointer(int a)
{
        a+= 1;
        if (a>= cRingBufCount) a= 0;
        return a;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top