【问题标题】:C# Threading - thread only runs properly when breakpoint existsC# 线程 - 线程仅在断点存在时才能正常运行
【发布时间】:2018-02-08 04:25:47
【问题描述】:

我一直无法让以下 C# 线程代码正常运行。我通过单击表单上的按钮来启动一个线程,该线程简单地声明一个浮点 x 并在循环中递增它,直到 threadRunning 设置为 false。当我再次单击该按钮时,我将 threadRunning 设置为 false。当循环完成时,线程将threadResult 设置为递增值x。然后我在表单上显示threadResult

问题是threadResult 在这种情况下总是设置为 256.0。如果我选择将x 增加0.0001f,那么threadResult 将始终设置为2048.0。每次线程运行时,这些固定值都会分配给threadResult除非我在递增的行x += 0.00001f; 上放置了一个断点。这可以是条件设置为 false 的条件断点;只要此行上存在启用的断点,x 就会正确递增并分配给threadResult

---编辑 1--- 为了阐明正确的行为是什么,仅当增量行上存在启用的断点时才会发生:threadResult 被分配的值等于增量行被命中的次数乘以增量值。因此,如果x 增加了 121 次,并且增量值为 0.00001f,则threadResult 应该变为 0.00121。当增量行上存在启用的断点并且我在调试模式下运行时,确实会发生。

另外,当我在发布模式下运行它时,当我单击按钮停止线程时程序会挂起,所以我假设我的线程实现完全有问题。我仍然会感谢任何关于我的代码可能存在问题的指针。我只是想写一些东西来测试停止线程。此外,我不想使用 BackgroundWorkers,因为我的线程代码不打算与 Windows 窗体一起使用。 ---结束编辑1---

谁能向我解释这里发生了什么?通过在线程外部将线程的循环控制变量设置为 false,我用来停止线程的方法是否可以?我在 Visual Studio 2017、2015 和 2013 中尝试过这段代码,结果都一样。

这里是代码。该表单仅包含一个名为 button1 的按钮和一个名为 textBox1 的文本框。

using System;
using System.Windows.Forms;
using System.Threading;

namespace ThreadingTesting
{
   public partial class Form1 : Form
   {
      public Form1()
      {
         InitializeComponent();
         button1.Click += Button1_Click;
      }

      private Thread thread;
      private bool threadRunning = false;
      private float threadResult = 0;

      private void Button1_Click(object sender, EventArgs e)
      {
         if (threadRunning)
         {
            threadRunning = false;
            thread.Join();
            textBox1.Text = "Result: " + threadResult.ToString("N4");
            button1.Text = "Start Thread";
         }
         else
         {
            thread = new Thread(new ThreadStart(ThreadedWork));
            thread.Start();
            textBox1.Text = "Thread Started!";
            button1.Text = "Stop Thread";
         }
      }

      private void ThreadedWork()
      {
         threadRunning = true;
         float x = 0.0f;
         while (threadRunning)
         {
            x += 0.00001f;
         }
         threadResult = x;
         return;
      }
   }
}

【问题讨论】:

  • 尝试查找关键字volatile
  • thread only runs properly when breakpoint exists 您看到的不当行为是什么?您正在寻求的正确行为是什么?
  • 如果您试图不阻止用户界面,您应该查看async/await
  • 这里的线程代码和数学代码都不正确。线程逻辑和浮点运算都很棘手,需要相当多的知识才能正确。不要使变量易变; 了解为什么如果您必须使变量 volatile 来解决线程问题,那么您可能使用了错误的工具来解决问题

标签: c# .net multithreading winforms visual-studio


【解决方案1】:

256 + 0.00001f 不幸导致256。这就是为什么它永远不会超过 256。

考虑使用double (d) 而不是float (f)。

【讨论】:

  • 或更好 - decimal (M)。 256M + 0.00001M.
  • 好的,使用double 有效。当我进行第一次编辑时,我一定没有更改所有双打。这仍然无法解释为什么它仅在存在断点时才与 floats 一起使用。
  • @bgg 那是因为您有两个线程在没有内存屏障 (stackoverflow.com/questions/3493931/…) 的情况下读取和写入同一个非volatile 变量。你会考虑改用BackgroundWorker 吗?
【解决方案2】:

答案就在这里

Why Thread.Join() DOES NOT hang my application when called on UI thread?

在 UI Thread 中调用了 Button1_Click 方法,因此其他线程将无法正常运行。

我认为你必须接近 Task 或 BackgroundWorker...

【讨论】:

    猜你喜欢
    • 2020-08-18
    • 2014-06-08
    • 1970-01-01
    • 1970-01-01
    • 2016-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-31
    相关资源
    最近更新 更多