gpt4 book ai didi

c++ - 使用者线程中的函数无法访问内存位置

转载 作者:太空宇宙 更新时间:2023-11-04 12:56:42 24 4
gpt4 key购买 nike

我有一些处理图像的代码。性能至关重要,因此我想使用BoundedBuffer实现多线程。图像数据存储为unsigned char*(由我用来处理图像数据的SDK指示)。

该问题发生在使用者线程中调用的processData函数中。在processData内部,还有另一个使用cudaMemcpy2D函数的函数(来自图像处理SDK)。 cuda函数始终会引发异常,指出访问冲突读取位置。

但是,如果我直接在生产者线程或processData中调用deposit,则cuda函数可以正常工作。当我从使用者线程调用processData时(根据需要),我从cuda函数获得了异常。我什至尝试从提取中调用processData,但出现了同样的异常。

我的猜测是,在生产者线程将数据deposit编码为rawImageBuffer之后,unsigned char*指向的内存以某种方式发生了变化,因此使用者线程(或fetch)实际上将错误的图像数据发送到processData(以及cuda函数)。

这是我的代码如下所示:

void processData(vector<unsigned char*> unProcessedData)
{
// Process the data
}

struct BoundedBuffer {
queue<vector<unsigned char*>> buffer;
int capacity;

std::mutex lock;

std::condition_variable not_full;
std::condition_variable not_empty;

BoundedBuffer(int capacity) : capacity(capacity) {}

void deposit(vector<unsigned char*> vData)
{
std::unique_lock<std::mutex> l(lock);

bool bWait = not_full.wait_for(l, 3000ms, [this] {return buffer.size() != capacity; }); // Wait if full

if (bWait)
{
buffer.push(vData); // only push data when timeout doesn't expire
not_empty.notify_one();
}
}

vector<unsigned char*> fetch()
{
std::unique_lock<std::mutex> l(lock);

not_empty.wait(l, [this]() {return buffer.size() != 0; }); // Wait if empty

vector<unsigned char*> result{};

result = buffer.front();
buffer.pop();

not_full.notify_one();

return result;
}
};

void producerTask(BoundedBuffer &rawImageBuffer)
{
for(;;)
{
// Produce Data
vector<unsigned char*> producedDataVec{dataElement0, dataElement1};
rawImageBuffer.deposit(producedDataVec);
} //loop breaks upon user interception
}

void consumerTask(BoundedBuffer &rawImageBuffer)
{
for(;;)
{
vector<unsigned char*> fetchedDataVec{};
fetchedDataVec = rawImageBuffer.fetch();
processData(fetchedDataVec);
} //loop breaks upon user interception
}

int main()
{
BoundedBuffer rawImageBuffer(6);

thread consumer(consumerTask, ref(rawImageBuffer));
thread producer(producerTask, ref(rawImageBuffer),

consumer.join();
producer.join();

return 0;
}

我对为什么会引发异常的猜测是否正确?我该如何解决?作为参考,每个 vector 元素均包含RGBa 8位格式的2448px X 2048px图像的数据。

更新:
  • 在某人在注释中指出unsigned char*指针可能无效之后,我发现指针所指向的地址实际上是真实的内存位置。在异常(exception)情况下,访问冲突读取位置X. X大于指针所指向的位置。
  • 经过更多调试后,我发现unsigned char*unprocessedData vector 中processData指向的内存并没有保持完整,指针地址正确,但是某些内存块不可读。我是通过在char中的unsigned char*中打印每个processData来找到的。当生产者线程调用processData时(这是cuda不会抛出异常的时候),所有char都会得到很好的打印(我正在打印2048 * 2448 * 4 char s,由上述图像分辨率和格式决定)。但是,当使用者线程调用processData时,打印char会引发相同的异常,该异常在第40个char周围(大约第40个,并非总是第40个)抛出。
  • 好吧,所以现在我很确定不仅我的指针指向实际的内存位置,而且我还知道指针所指向的第一个内存块将预期值保存的次数与我测试过的次数相同。为了测试这一点,我故意在producerTask中将测试值(例如int 42或char *)写入0指向的unsigned char* th存储块。在processData函数中,我检查内存块是否仍然包含测试值并且是否包含测试值。因此,现在我知道由于某些未知原因,指针指向的某些存储块变得无法访问。另外,我的测试并不能证明第一个内存块不会变得无法访问,只是我经过的几次测试并没有变得不可访问。 用于更新1到3的TLDR :unprocessedImage指针有效,它们指向实际的内存地址,并且还指向保存期望值的内存地址。
  • 另一个调试尝试。现在,我使用Visual Studio的内存窗口以可视方式检查数据。调试器告诉我unProcessedData[0]指向0x00000279d7c76070。这是0x00000279d7c76070周围的内存的样子:

    内存看起来很明智,可以清楚地看到RGBa格式,图像全是黑色,因此RGB通道接近0是有意义的,而alphaff。我向下滚动了很长时间,以查看内存的样子,一直到0x00000279D8F9606F数据看起来不错(RGBa值符合预期)。 0x00000279D8F9606F编号也很有意义,因为0x00000279D8F9606F-0x00000279d7c76070 = 0d20054015,这意味着应该有20054016有效char s(2048高度* 2448宽度* 4通道= 20054016)。好的,到目前为止很好。请注意,所有这些都是在运行cuda函数之前完成的。在完成cuda函数之后,我得到了相同的异常:访问冲突读取位置0x00000279D80B8000。请注意,0x00000279D80B80000x00000279d7c760700x00000279D8F9606F之间,这是我目视检查是否正确的内存部分。现在,在运行cuda函数之后,0x00000279d7c760700x00000279D8F9606F之间的内存如下所示:
  • 当我在调用cuda函数之前对cout中的任何内容进行processData编码时。指针指向的内存会更改。如下图所示,所有char都等同于0xdd。 MSDN上的This页面上说The freed blocks kept unused in the debug heap's linked list when the _CRTDBG_DELAY_FREE_MEM_DF flag is set are currently filled with 0xDD.
    但是,当我从生产者线程调用processData时,我对cout进行任何操作后,指向的内存不会更改。

  • 现在,对该问题最受好评的评论是告诉我学习有关指针的更多信息。我目前正在这样做(希望我的更新可能会建议这样做),但是我需要了解哪些主题?我知道指针是如何工作的。我知道我的指针指向有效的内存位置(请参阅更新2)。我知道指针指向的某些内存块变得无法读取(请参阅更新3)。但是我不知道为什么无法访问内存块。特别是,我不知道为什么仅当从使用者线程调用 processData时它们才变得不可访问(请注意,从生产者线程调用 processData时不会引发异常)。我还能做些什么来帮助缩小这个问题?

    最佳答案

    问题很简单,n.m。的评论引导我朝着正确的方向前进,对此我感到非常感谢。

    在我的更新中,我提到使用cout打印任何内容都会导致数据损坏。虽然,这似乎正在发生,但是在fetchdeposit中设置了一些断点之后,我对真实情况有了一个完整的了解。

    我生成图像数据的方式是使用相机随附的另一个SDK,该SDK为我提供了包装指针类型的图像数据。然后,我转换了图像格式,然后解包了转换后的图像以获取指向原始图像的指针。然后,将指向原始图像的指针存储到producedDataVec中,并通过deposit将其存储到rawImageBuffer中。问题是,一旦转换的图像超出范围,我的数据就会被破坏。因此,cout语句对破坏我的数据并不真正负责。断点无处不在,转换后的镜像超出范围后,我可以看到数据已损坏。为了解决这个问题,现在我的生产者直接deposit将包装好的指针指向缓冲区。使用者fetch是包装的指针,通过在使用者中转换格式获得转换后的图像,然后获得原始图像指针。现在,仅在返回processData后,转换后的图像才超出范围,因此永远不会引发异常。

    关于c++ - 使用者线程中的函数无法访问内存位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46185191/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com