【问题标题】:Two Threads are Slowing Each Other C#两个线程相互减慢 C#
【发布时间】:2020-02-10 08:47:57
【问题描述】:

我在 Picturebox 中有 2 张图片。当我选中复选框时,风扇开始旋转。 我创建了两个不同的线程(但它们在做同样的工作)。如果我只检查其中一个,它工作没有问题,但如果我同时检查它们两个,它们会相互减慢。我希望线程不会相互影响。我该如何处理这种情况?

Thread rotateImageThread = new Thread(new ParameterizedThreadStart(RotateImageThreadFunction));
Thread radialFanTurningThread = new Thread(new ParameterizedThreadStart(RadialFanTurningThreadFunction));
static ManualResetEvent pauseResumeThreadForFreezerFan = new ManualResetEvent(true);
static ManualResetEvent pauseResumeThreadForRadialFan = new ManualResetEvent(true);
static bool rotateImageRunFlag = false;
static bool radialFanRunFlag = false;
bool startThreadAtStartFlag = true;
bool startThreadAtStartForRadialFanFlag = true;

private void CB_freezer_fan_CheckedChanged(object sender, EventArgs e)
{
    if (cb_freezer_fan.Checked == true)
    {
        StartThreadAtStart();
        pb_FreezerFan.Visible = false;
        pb_FreezerFanRunning.Visible = true;
        setRotateImageRunFlag(true);
        pauseResumeThreadForFreezerFan.Set();
    }
    else
    {
        pb_FreezerFan.Visible = true;
        pb_FreezerFanRunning.Visible = false;
        setRotateImageRunFlag(false);
        pauseResumeThreadForFreezerFan.Reset();
    }
}

private static void RotateImageThreadFunction(object objectToInside)
{
    PictureBox pictureBox = (PictureBox)objectToInside;
    int rotateAngle = 0;
    while(true)
    {
        pauseResumeThreadForFreezerFan.WaitOne(Timeout.Infinite);
        if (getRotateImageRunFlag() == true)
        {
            rotateAngle = pictureBox.Visible == false ? 0 : rotateAngle;
            pictureBox.Image = RotateImage(global::SimulationInterface.Properties.Resources.FreezerFanRunning1, rotateAngle);
            rotateAngle += 5;
            Thread.Sleep(10);
            rotateAngle = (rotateAngle == 360) ? 0 : rotateAngle;
        }
    }
}

public static Image RotateImage(Image img, float rotationAngle)
{
    //create an empty Bitmap image
    Bitmap bmp = new Bitmap(img.Width, img.Height);

    //turn the Bitmap into a Graphics object
    Graphics gfx = Graphics.FromImage(bmp);

    //now we set the rotation point to the center of our image
    gfx.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);

    //now rotate the image
    gfx.RotateTransform(rotationAngle);

    gfx.TranslateTransform(-(float)bmp.Width / 2, -(float)bmp.Height / 2);

    //set the InterpolationMode to HighQualityBicubic so to ensure a high
    //quality image once it is transformed to the specified size
    //gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;

    //now draw our new image onto the graphics object
    gfx.DrawImage(img, new Point(0, 0));

    //dispose of our Graphics object
    gfx.Dispose();

    //return the image
    return bmp;
}

public void StartThreadAtStart()
{
    if (startThreadAtStartFlag == true)
    {
        rotateImageThread.Start(pb_FreezerFanRunning);
        rotateImageThread.Priority = ThreadPriority.Lowest;
        startThreadAtStartFlag = false;
    }
}

private static void RadialFanTurningThreadFunction(object objectToInside)
{
    PictureBox pictureBox = (PictureBox)objectToInside;
    int rotateAngle = 0;
    while (true)
    {
        pauseResumeThreadForRadialFan.WaitOne(Timeout.Infinite);
        if (getRadialFanRunFlag() == true)
        {
            pictureBox.Image = RotateImageForRadialFan(global::SimulationInterface.Properties.Resources.ventilating_fan, -rotateAngle);
            rotateAngle += 5;
            Thread.Sleep(10);
            rotateAngle = (rotateAngle == 360) ? 0 : rotateAngle;
        }
        System.Diagnostics.Trace.WriteLine(rotateAngle);
    }
}

private void cb_RadialFan_CheckedChanged(object sender, EventArgs e)
{
    ChangePictureboxImageWithCheckbox(cb_RadialFan, pb_HvacFan, pb_HvacFanRunning);
    if (cb_RadialFan.Checked == true)
    {
        StartThreadAtStartForRadialFan();
        setRadialFanRunFlag(true);
        pauseResumeThreadForRadialFan.Set();
    }
    else
    {
        setRadialFanRunFlag(false);
        pauseResumeThreadForRadialFan.Reset();
    }
}

public static Image RotateImageForRadialFan(Image img, float rotationAngle)
{
    //create an empty Bitmap image
    Bitmap bmp = new Bitmap(img.Width, img.Height);

    //turn the Bitmap into a Graphics object
    Graphics gfx = Graphics.FromImage(bmp);

    //now we set the rotation point to the center of our image
    gfx.TranslateTransform((float)bmp.Width / 2, (float)bmp.Height / 2);

    //now rotate the image
    gfx.RotateTransform(rotationAngle);

    gfx.TranslateTransform(-(float)bmp.Width / 2, -(float)bmp.Height / 2);

    //set the InterpolationMode to HighQualityBicubic so to ensure a high
    //quality image once it is transformed to the specified size
    //gfx.InterpolationMode = InterpolationMode.HighQualityBicubic;

    //now draw our new image onto the graphics object
    gfx.DrawImage(img, new Point(0, 0));

    //dispose of our Graphics object
    gfx.Dispose();

    //return the image
    return bmp;
}

public void StartThreadAtStartForRadialFan()
{
    if (startThreadAtStartForRadialFanFlag == true)
    {
        radialFanTurningThread.Start(pb_HvacFanInner);
        radialFanTurningThread.Priority = ThreadPriority.Lowest;
        startThreadAtStartForRadialFanFlag = false;
    }
}

public static bool getRotateImageRunFlag()
{
    return rotateImageRunFlag;
}

public static void setRotateImageRunFlag(bool state)
{
    rotateImageRunFlag = state;
}

public static bool getRadialFanRunFlag()
{
    return radialFanRunFlag;
}

public static void setRadialFanRunFlag(bool state)
{
    radialFanRunFlag = state;
}

【问题讨论】:

  • 我发现您的代码有一个问题,但它可能无关(但又可能不相关),您正在从辅助线程更改 UI 对象。这需要在这些 UI 对象上使用 Invoke 方法进行同步。
  • 要调试你的代码,请一点一点地从线程中删除一些位,以确定是什么影响了另一个线程。
  • 你的代码能正常运行吗?使用非 ui 线程应该无法更改 UI。你有两个非ui线程来改变它。使用 Windows.Form.Timer 会更好地更改 UI,因为您不需要处理线程问题。

标签: c# multithreading asynchronous


【解决方案1】:

不要在后台线程中修改 UI。 如果这是 winform 应用程序,请使用 System.Windows.Forms.Timer。 如果这不是 winform 应用程序,请为您找到一个调用 UI 线程。

// Initial code
var tmr = new System.Windows.Forms.Timer();
tmr.Interval = 10;
tmr.Tick += Tmr_Tick;
tmr.Enabled = true;


private void Tmr_Tick( object sender, EventArgs e )
{
  // Rotate cb fan if checked
  // Rotate radial fan if checked
}

为了解释为什么你的两个更新函数会互相拖慢,我假设你的代码 sn-p 是不完整的。应该有Invoke来改变控制。

  1. 调用很耗时。
  2. 您可能会不自觉地在Invoke 中添加Thread.Sleep,这会导致您的UI 线程在控件更新后休眠10 毫秒。 有两个线程,每个线程更新并休眠 10 毫秒,因此需要 20 毫秒才能看到您的控件发生变化。它可能比 20 毫秒更糟。

【讨论】:

  • 我尝试了这个解决方案并且它的工作。他们并没有减慢对方的速度。谢谢!但它不像我尝试使用 Threads 那样流畅。
  • 如果你想让它运行更流畅,减少间隔,使用预先计算好的图片,而不是通过图形旋转。同时搜索DoubleBuffer,这可能会提高你的图片更新速度。
  • 我已经尝试过 DoubleBuffer,但它并没有真正起作用。我会搜索预先计算好的图片。
猜你喜欢
  • 1970-01-01
  • 2021-08-20
  • 1970-01-01
  • 2014-06-09
  • 1970-01-01
  • 1970-01-01
  • 2016-02-18
  • 1970-01-01
  • 2018-10-25
相关资源
最近更新 更多