cameron314 / concurrentqueue

A fast multi-producer, multi-consumer lock-free concurrent queue for C++11
Other
9.87k stars 1.69k forks source link

struct data get wrong data from try_dequeque #323

Closed ouclbc closed 1 year ago

ouclbc commented 1 year ago

struct like this:

typedef struct depth_buffer
{
    void *imgdata;
    unsigned int width;
    unsigned int height;
    unsigned int bufsize;
}depth_buffer;

when I use

moodycamel::ConcurrentQueue<depth_buffer*> depthBufQueque;
depthBufQueque.enqueue
depth_buffer* depthBuf = nullptr;
    bool ret = depthBufQueque.try_dequeue(depthBuf);

I get wrong imagedta,but width and height is right, I don not why?

cameron314 commented 1 year ago

Are you sure the object whose pointer you enqueue is still valid after it's dequeued?

Please provide as complete an example as possible.

ouclbc commented 1 year ago

the stb lib is from https://github.com/nothings/stb and the picture size is 120*240

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image.h"
#include "stb_image_write.h"
#include "concurrentqueue.h"
#include <readerwriterqueue.h>

using namespace std;

typedef struct depth_buffer
{
    void *imgdata;
    unsigned int width;
    unsigned int height;
    unsigned int bufsize;
}depth_buffer;
moodycamel::ConcurrentQueue<depth_buffer*> depthBufQueque;

moodycamel::ReaderWriterQueue<depth_buffer*> q(10);

int savePic(char const *filename, int width, int height, const void *data){
    //int result = stbi_write_png(filename, width, height, 4, data, width*4);
    int result = stbi_write_jpg(filename, width, height, 3, data, 100);
    printf("result is %d\n",result);
    return result;
}
std::thread producer([&]() {
    depth_buffer *db;
          db = (depth_buffer*)malloc(sizeof(depth_buffer));
          db->width = 120;
          db->height = 240;
          db->bufsize= 120*4*240;
          db->imgdata = malloc(db->bufsize);
          int res = 0;
          int w,h,c;
    unsigned char *data = stbi_load("test_120_240.jpeg", &w, &h, &c, 4);
    memcpy(db->imgdata,data,w*h*4);
    depthBufQueque.enqueue(db);
    printf("producer end\n");
    depth_buffer* depthBuf = nullptr;
    bool ret = depthBufQueque.try_dequeue(depthBuf);
    printf("ret is %d\n",ret);
    if(ret && depthBuf != nullptr){
        int result = savePic("dump.jpeg", depthBuf->width,depthBuf->height,depthBuf->imgdata);
    }
});
std::thread consumer([&]() {
    printf("consumer start\n");
    /*depth_buffer* depthBuf = nullptr;
    bool ret = depthBufQueque.try_dequeue(depthBuf);
    printf("ret is %d\n",ret);
    if(ret && depthBuf != nullptr){
        int result = savePNG("dump.png", depthBuf->width,depthBuf->height,depthBuf->imgdata);
    }*/
});
int main(void)
{
    printf("start\n");
    producer.join();
    consumer.join();
    printf("end\n");
    return 0;
}
cameron314 commented 1 year ago

Looks like stbi_write_jpg is being called with a channel count of 3 (RGB), but the image data was read into a buffer using a channel count of 4 (RBGA).

Don't see anything wrong with the use of the queue here.

ouclbc commented 1 year ago

I seem find the error, when I call free after enqueue,then I get the wrong data,if not ,the result is correct.and my question is when to free ? or never call ?

cameron314 commented 1 year ago

Free after you're done with the object. In this case, after the dequeue and write to disk operations. Ideally this would be managed automatically through the use of smart pointers, like std::unique_ptr or some other form of RAII.