我正在研究客户端服务器应用程序。在某些时候,在某些机器上,当有超过5个客户端请求数据时,它似乎陷入僵局。如果我介入调试问题,那么程序似乎正在处理。只需设置一个断点,我知道程序正在执行,并导致它几次点击断点导致它完成。如果我在代码中的某些点插入Thread.Sleep(0),主要是围绕一些cpu密集循环,它似乎几乎完全解决了问题。我现在遇到的一个问题是,如果我调用Thread.Sleep(0)太多,它可能会减慢代码速度。如果我不够称呼它,代码似乎陷入僵局。虽然我可以验证它不是死锁,因为如果我进入代码,它会导致问题消失,因为我暂停了一个线程。
是否有一种很好的方法可以准确追踪造成这种情况的原因。它似乎只发生在运行Vista的笔记本电脑上,而不是在运行Windows XP的桌面上。但是,调试是不可能的,因为简单地插入代码会导致问题消失。我读过一些注释,调用Thread.Sleep(0)是一个不好的做法,并不应该是必要的,我不喜欢把巫术类型的代码放到我的应用程序中,我不明白为什么它必须在那里。任何指针都将非常感激。
[编辑] 我还可以验证代码在“死锁”时仍然在运行,因为如果我留下足够长的时间,它就会完成,只需要花费的时间就要多出几个数量级。我的意思是,当它处于这种“死锁”模式时,它实际上至少慢了100倍。 CPU固定在80-95%,所以它正在工作,尽管它正在做的事情超出我的范围,因为它需要永远完成任务。
[更多信息] 仅仅因为这里的每个人都坚持认为这是一个死锁,我删除了所有锁定的代码。只有几行代码可以进行任何锁定。螺纹在大多数情况下完全独立工作,因此完全移除锁定并没有太大的作用。问题仍然存在。在我的代码中没有更多的synclocks,没有更多的互斥锁,我看到没有更多的东西会导致死锁,但问题仍然存在。而且它没有陷入僵局。虽然它耗尽了所有处理器资源,但它运行速度虽然非常缓慢。
答案 0 :(得分:11)
Thread.Sleep(0)是一个收益率。我猜这会重新排列你打电话的方式以避免一些问题。我想如果你发布了带有yield的代码并在1000台机器上运行它,你会得到很多错误报告。我猜你需要一些类型的锁/关键部分来避免你的死锁,因为你的代码不是线程安全的。那可能是你正在打电话的图书馆。
答案 1 :(得分:4)
如果不查看整个代码库,就无法回答。
调用Thread.Sleep是一个 HORRIBLE 练习,你不应该这样做。您基本上会转移导致死锁的代码时间,而不是实际解决死锁条件。
调试没有显示问题的原因是当调试器停止时,代码中的所有线程都会停止,这样也会影响程序执行的时间。
您要在此处执行的操作是在此处插入日志记录代码,以跟踪代码在不同线程上的执行路径,并在此基础上确定死锁的位置。
答案 2 :(得分:3)
那个循环内部是什么?如果要检查循环中的某个字段以同步多个线程,则会出现类似问题:
while (_field); // waiting for _field change in another thread
此解决方案将非常缓慢,并且调用Thread.Sleep(0)不是解决方案,但在某些情况下可能是黑客攻击。如果通过调用某个同步对象(例如ManualResetEvent)的WaitHandle.WaitOne()方法更改该同步循环,并且在另一个线程中向此句柄发出信号,则可以正确修复此问题。也许你的问题是这样的?请提供您的部分代码。
答案 3 :(得分:2)
当它陷入困境时,同时运行的线程数是多少? 如果您有太多线程,CPU可能会花费所有时间进行上下文切换。另外,每个线程你会咀嚼1+ MB的内存。
答案 4 :(得分:1)
每次锁定互斥锁时尝试打印一行,并在解锁时打印另一行。记得在打印时包含函数名称和线程ID。应该让你知道它什么时候锁定。看起来像一个竞争状态调用sleep(0)仍然会导致CPU使用循环来处理对函数的调用。因此造成固有的睡眠。
答案 5 :(得分:1)
我认为是时候离开电脑,再到白板。分析每个元素的锁定方式以及它在什么条件下仔细释放锁定。五个线程可能是一个难题,所以也许看看两个线程是否会导致相同的情况。有些东西没有正确锁定,你需要找到它。
除非你的代码不值得付出这么大的努力,否则请将Thread.sleep()留在那里,因为它并没有真正损害你在宏观方案中的表现。
答案 6 :(得分:1)
您肯定有需要解决的线程问题。调用thread.Sleep(0)会导致调度程序启动。这可能会使每个线程都有足够的运行时间来运行。我不会只是把睡眠留在那里并留在那里,因为那些是那种有效的东西,然后一个完全不相关的变化最终会破坏它。
答案 7 :(得分:1)
除非硬件强迫你,否则你永远不应该使用sleep()。
尝试以不同的方式思考问题。考虑需要在线程之间共享哪些数据,并考虑将数据(IE,复制它)发送给感兴趣的各方而不是共享访问的方式..如果你这样做,你实际上可能不需要任何互斥... < / p>
请记住,局部变量存在于不同的堆栈中,但函数中的静态基本上是全局变量(当然,您需要仔细查看全局变量)。
答案 8 :(得分:0)
也许尝试使用像Typemock Racer这样的工具?
免责声明:我之前从未使用过该工具。
答案 9 :(得分:0)
是的,您可能遇到过调度程序过载。
我真诚地希望不会。