时间问题?程序在 Visual Studio 中运行良好,但不是独立的
Posted
技术标签:
【中文标题】时间问题?程序在 Visual Studio 中运行良好,但不是独立的【英文标题】:Timing issue? Program runs fine in Visual Studio but not standalone 【发布时间】:2014-11-19 16:49:50 【问题描述】:我有一个本地 C++ DLL。 DLL 创建一个从外部设备重复读取数据的线程。如果数据读取速度不够快,设备可能会溢出。
“读取”循环如下所示:
while (true)
read_from_device();
buffer_data();
Sleep(5); //Allow data to accumulate
我还有一个使用上述 DLL 的 C# 应用程序。它调用 DLL 中的一个函数来启动“读取”线程,然后定期调用 DLL 中的另一个函数来检查是否已从外部设备读取所有数据。
应用程序和 DLL 在 Visual Studio(本例中为 2008)中的“调试”模式下构建。
如果我通过 Visual Studio 运行应用程序,一切都很好:从外部设备读取数据并且不会发生溢出。
当我“独立”运行同一个应用程序(通过直接运行 .exe)时,我遇到了溢出。
我认为唯一的区别是在第一个实例中,Visual Studio 调试器会自动附加到应用程序?请记住,我没有设置断点。
我的应用程序中一定存在时间问题,当调试器附加到它时,它以某种方式得到纠正?
我该如何调试这个问题?
通过 Visual Studio 运行应用程序与直接运行应用程序之间还有哪些区别?
编辑:
下面是更详细的代码:
int buffer[MAX_EVENTS*2];
int bufferIndex = 0;
int eventsReturned = 0;
BufferObject *pNewBuffer;
while (bPollData)
read_data(buffer[bufferIndex], &eventsReturned);
bufferIndex += eventsReturned;
if (bufferIndex >= MAX_EVENTS)
pNewBuffer = new BufferObject(buffer, bufferIndex);
myList.AddTail(pNewBuffer);
bufferIndex = 0;
Sleep(5);
...
...
class BufferObject
int *buffer;
int bufferSize;
public:
BufferObject(int* source, int size)
buffer = new int[size];
bufferSize = size;
memcpy(buffer, source, size);
;
【问题讨论】:
通常和内存有关。无论如何,我们需要查看更多代码。 您是否正在使用优化编译您的 DLL?您是否尝试过移除睡眠,即使它在连接到 VS 时工作正常? 检查 Windows 日志中是否存在导致崩溃的错误 你为什么要睡在那里?当然,如果你想避免溢出,你应该尽可能快地阅读。顺便说一句,你最好让你的读取循环检查手动重置事件,这样你就可以在完成后干净地关闭你的线程...... @LenHolgate 睡眠是为了让数据积累。如果我过于频繁地从设备读取数据,则设备会将所有时间都花在服务请求上,而不是收集数据。该线程确实有更好的关闭方式,我只是没有包含它。 【参考方案1】: Sleep(5);
嗯,这就是你问题的 99%。你已经知道当你的代码运行速度快时你会遇到问题。你人为地减慢了它的速度,以便在虫子上贴上创可贴。但是,当您执行使您的代码运行得更快的else 操作时,它再次中断当然不应该感到惊讶。就像不附加调试器一样运行它。
您可能甚至不知道 5 就足够了。这是一个相当随机的数字,您的程序实际上睡眠的时间很少恰好是 5 毫秒。默认睡眠精度为 15.625 毫秒,但当另一个程序调用 timeBeginPeriod() 时可能会改变。只需运行一个浏览器就足够了,众所周知,Chrome 会改变中断率。所以你突然跑得快了 3 倍,而不是 15 毫秒。破坏你的程序。您不希望 Chrome 破坏您的程序;)
你必须解决真正的问题。这肯定就像您只是将设备发送给您的多少字节都放入一个 BufferObject 中。因此,如果您的程序运行得很快,您将获得 许多 个缓冲区对象,每个缓冲区对象只有一点点数据。这可能会对使用数据的任何代码造成严重破坏。一个传统的问题是程序的 UI 变得紧张,疯狂地试图跟上所需的重绘。
如果没有从问题中获得足够的洞察力,随机猜测是您必须首先缓冲设备响应,直到它积累足够的字节以使其值得将其粘贴到 BufferObject 中。如果您继续使用 Sleep() 创可贴,则选择一个向下舍入的 15.625 整数倍的睡眠量。比如 15、31、46。
【讨论】:
就在这一刻,我正在记录调用 read_data() 函数之间的时间,并得到 156000us。我没有意识到这一点。如果我删除 Sleep(n),设备会花费所有时间来服务 read_data() 请求,这对其收集数据的其他(主要)任务产生不利影响。所以我需要以某种方式限制调用 read_data() 的频率。非常感谢您的回答,这可能会让我进步。 设备是否以恒定或可变速率收集?您可以尝试根据返回的数据点数动态调整延迟。因此,如果它从一次调用中返回超过 X,则您立即再次调用它,否则您等待...【参考方案2】:您可能会遇到收集数据(并构建缓冲区列表)的线程与应用程序用于访问(并可能删除)缓冲区的线程之间缺乏同步的问题。
您可能需要在访问缓冲区列表时添加一些锁定。似乎您有一个“活动”缓冲区,只有数据读取器线程可以写入(缓冲区),当它已满时,您将此数据复制到一个新的缓冲区对象中并将其添加到列表中。您可能应该锁定列表的使用(该列表可能在内部包含正确的同步,但从您的代码示例中不清楚)。
循环似乎无法通知 read_data() 函数它传入的缓冲区中的剩余空间,这可能是导致内存溢出的原因。
就个人而言,因为无论如何您都在动态分配缓冲区对象,所以我会完全跳过内存副本,只需保存一个活动缓冲区对象并直接读入,而不是读入临时缓冲区,然后将其复制到缓冲区对象中。
鉴于问题的性质和代码的缺乏,除了猜测之外不可能做更多的事情。
【讨论】:
谢谢伦。该列表实际上永远不会同时访问,因此我不需要锁定对它的访问 - 但是我对此束手无策,所以无论如何我都会尝试一下。我还将再看一下代码的 read_data() 方面。你关于多余的内存副本的观点是一个很好的观点,我一定会做出改变。我很欣赏由于缺少代码而难以评估问题,但我最初的想法是代码实际上是合理的,只是调试器的存在与否改变了应用程序的时间。我没有考虑内存问题 @digital_fate:请注意,如果您的代码因调试器更改时间而失败,则代码不正确。它应该独立于确切的时间来工作——Windows 不是一个实时操作系统,它不能给你任何保证。今天是调试器更改时间,明天是 Windows 更新。 Jeroen,或者,很可能,只是在另一台机器上运行它 :)以上是关于时间问题?程序在 Visual Studio 中运行良好,但不是独立的的主要内容,如果未能解决你的问题,请参考以下文章
在 Visual Studio 2010 调试器中运行时不会显示 Windows 公用文件对话框
Windows 应用程序在 Visual Studio 2019 中运行时工作,在我在本地构建和运行后工作,但是当提交到应用商店并下载时,它不运行
System.NullReferenceException 用于在 Windows 服务器 IIS 上运行但在 Visual Studio IIS Express 中运行时在本地运行的 .NET 服务
微软正式发布Visual Studio Kubernetes工具包