【问题标题】:Send message through Ring (Circular) Buffer between Threads (in C)通过线程之间的环形(循环)缓冲区发送消息(在 C 中)
【发布时间】:2017-06-05 10:01:14
【问题描述】:

我需要使用 WinAPI 和 Ring Buffer 将消息从主线程发送到我创建的线程。

我为我的环形缓冲区定义了结构并编写了函数。 环形缓冲区 - 它包含头、尾、大小和指向结构描述符的指针,该结构描述符具有数据长度和数据本身。由于我需要向 CreateThread 函数发送 2 个参数,因此我创建了第三个结构 ThreadParams 来保留 2 个参数。

我想让这些结构保持现在的样子,不可更改。

typedef struct _Descriptor
{
    uint32_t dataLen;
    void * data;
} Descriptor;

typedef struct _ringBuffer
{
    Descriptor *bufferData;
    int head;
    int tail;
    int size;
} ringBuffer;

typedef struct _ThreadParams
{
    void * ptr1;
    void * ptr2;
} ThreadParams;

有我对Ring Buffer函数的实现:

void bufferFree(ringBuffer *buffer)
{
    free(buffer->bufferData);
}

void ringInitialization(ringBuffer *buffer, int size)
{
    buffer->size = size;
    buffer->head = 0;
    buffer->tail = 0;
    buffer->bufferData = (Descriptor*)malloc(sizeof(Descriptor) * size);
}

int pushBack(ringBuffer *buffer, void * data) // fill buffer
{
    buffer->bufferData[buffer->tail++] = *(Descriptor*)data;
    if (buffer->tail == buffer->size)
    {
        buffer->tail = 0;
    }
    return 0;
}

int popFront(ringBuffer *buffer)
{
    if (buffer->head != buffer->tail)
    {
        buffer->head++;
        if (buffer->head == buffer->size)
        {
            buffer->head = 0;
        }
    }
    return 0;
}

我的主要:我检查了我可以发送几个字节(内存在线程之间共享),现在我需要通过 Ring Buffer 发送一条大消息(> BUFF_SIZE),这是我在 while() 中尝试做的循环。这是一个问题:我应该怎么做?我的东西不起作用,因为我在 printf() 函数中捕获了一个异常(内存访问冲突)。

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <strsafe.h>
#include <stdint.h>

#define RING_SIZE 256
#define BUFFER_SIZE 1024

DWORD WINAPI HandleSendThread(LPVOID params);

uint8_t * getPointer(uint8_t *buffer, uint32_t index)
{
    uint8_t * ptr = ((uint8_t*)buffer) + index * BUFFER_SIZE;
    return ptr;
}

int main(int argc, char * argv[])      
{
    //Descriptor * ringData = (Descriptor *)malloc(sizeof(Descriptor) * RING_SIZE);

    ringBuffer ring;
    ringInitialization(&ring, RING_SIZE);
    void * packetBuffer = malloc(BUFFER_SIZE * RING_SIZE);
    uint8_t * currentBuffer = getPointer(packetBuffer, 0);
    uint8_t * str = "Mr. and Mrs. Dursley, of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much. They were the last people you'd expect to be involved in anything strange or mysterious, because they just didn't hold with such nonsense. Mr.Dursley was the director of a firm called Grunnings, which made drills.He was a big, beefy man with hardly any neck, although he did have a very large mustache.Mrs.Dursley was thin and blonde and had nearly twice the usual amount of neck, which came in very useful as she spent so much of her time craning over garden fences, spying on the neighbors.The Dursleys had a small son called Dudley and in their opinion there was no finer boy anywhere.";

    strcpy(currentBuffer, str);
    ring.bufferData[0].data = currentBuffer;
    ring.bufferData[0].dataLen = strlen(str);

    int currentSize = 0;
    int ringSize = RING_SIZE;
    while(ring.bufferData[0].data != '\0')
    {
        for (int i = currentSize; i < ringSize; i + RING_SIZE)
        {
            pushBack(&ring, currentBuffer); 
            printf("h = %s, tail = %s, dataBuffer = %s\n", (char*)ring.head, (char*)ring.tail, (char*)ring.bufferData[i].data);
        }
        currentSize = ringSize;
        ringSize = 2 * ringSize;
        popFront(&ring);
    }

    ThreadParams params = { &ring, packetBuffer };
    HANDLE MessageThread = 0;
    MessageThread = CreateThread(NULL, 0, HandleSendThread, &params, 0, NULL);
    if (MessageThread == NULL)
    {
        ExitProcess(MessageThread);
    }

    WaitForSingleObject(MessageThread, INFINITE);
    CloseHandle(MessageThread);
    system("pause");
    return 0;
}

还有我的 CreateThread 函数:

DWORD WINAPI HandleSendThread(LPVOID params)
{
    ringBuffer * ring = ((ThreadParams*)params)->ptr1;
    void * buffer = ((ThreadParams*)params)->ptr2;
    //ring->bufferData[0].dataLen = sizeof(buffer) + sizeof(ring->bufferData[0])*1024;

    printf("Shared memory check: ringBuffer data = \"%s\", \nlength = %d\n", (char*)ring->bufferData[0].data, ring->bufferData[0].dataLen);
    return 0;
}

【问题讨论】:

  • params 是一个局部变量,当线程开始运行时它不再存在。 ++ 运算符是读-修改-写,因此不是线程安全的。
  • 'ring.bufferData[0].dataLen = strlen(str);'不,不是。
  • @HansPassant 是的,但是主线程卡在 WaitForSingleObject 上,所以本地变量的生命周期是可以的。
  • 我没有向下滚动足够远来看到等待。因此,使用线程根本没有任何意义。嗯,这应该有助于解决问题:)
  • @HansPassant 我还没有弄清楚它是如何工作的。似乎没有任何“数据可用”信号,没有信号量或其他任何东西,所以我看不出如果没有数据消费者会做什么;(

标签: c windows winapi circular-buffer


【解决方案1】:

您最直接的问题是pushBack() 中的代码(它期望data 指向Descriptor)与您的main 函数中的代码之间的不一致,后者传递了一个指向字符串的指针。

如果你正确地声明了pushBack(),即,

void pushBack(ringBuffer *buffer, Descriptor * data)
{
    buffer->bufferData[buffer->tail++] = *data;
    if (buffer->tail == buffer->size)
    {
        buffer->tail = 0;
    }
}

那么编译器就能够警告您存在差异。

这里还有一个无限循环:

for (int i = currentSize; i < ringSize; i + RING_SIZE)

你可能是说

for (int i = currentSize; i < ringSize; i += RING_SIZE)

...尽管在我看来它仍然不会做任何明智的事情。我也不明白外循环的目的,它将指针与字符进行比较。

【讨论】:

    【解决方案2】:

    找到解决办法

    int main(int argc, char * argv[])
    {
        ringBuffer ring;
        ringInitialization(&ring, RING_SIZE);
        void * packetBuffer = malloc(BUFFER_SIZE * RING_SIZE);
        Descriptor temp = { 0 };
        uint8_t * currentBuffer = getPointer(packetBuffer, 0);
        uint8_t * str = "Mr. and Mrs. Dursley, of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much. They were the last people you'd expect to be involved in anything strange or mysterious, because they just didn't hold with such nonsense. Mr.Dursley was the director of a firm called Grunnings, which made drills.He was a big, beefy man with hardly any neck, although he did have a very large mustache.Mrs.Dursley was thin and blonde and had nearly twice the usual amount of neck, which came in very useful as she spent so much of her time craning over garden fences, spying on the neighbors.The Dursleys had a small son called Dudley and in their opinion there was no finer boy anywhere.";
    
        strcpy(currentBuffer, str);
        temp.dataLen = strlen(str);
        temp.data = currentBuffer;
    
        pushBack(&ring, &temp);
        ThreadParams params = { &ring, packetBuffer };
        HANDLE MessageThread = 0;
        MessageThread = CreateThread(NULL, 0, HandleSendThread, &params, 0, NULL);
        if (MessageThread == NULL)
        {
            ExitProcess(MessageThread);
        }
        WaitForSingleObject(MessageThread, INFINITE);
        CloseHandle(MessageThread);
        system("pause");
        return 0;
    }
    
    DWORD WINAPI HandleSendThread(LPVOID params)
    {
        ringBuffer * ring = ((ThreadParams*)params)->ptr1;
        void * buffer = ((ThreadParams*)params)->ptr2;
        Descriptor * temp = &ring->bufferData[ring->head];
    
        for (int i = 0; i < temp->dataLen; i++)
        {
            printf("%c", ((char*)temp->data)[i]);
        }
        printf("\n");
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2012-10-20
      • 1970-01-01
      • 2016-12-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-29
      • 2019-07-05
      相关资源
      最近更新 更多