c# - 两个线程相互减慢 C#
问题描述
我在 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。如果这是 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
}
为了解释为什么您的两个更新功能彼此减慢,我假设您在帖子中的代码片段不完整。应该有Invoke
变更控制。
- 调用很耗时。
- 您可能会在控件更新后无意识地添加
Thread.Sleep
导致Invoke
UI 线程休眠 10 毫秒的结果。有两个线程,每个线程更新并休眠 10 毫秒,因此需要 20 毫秒才能看到您的控件发生变化。它可能比 20 毫秒更糟。
推荐阅读
- c++ - C++ 中的 protobuf 与 google::protobuf::Message 的动态绑定
- android - 如何检测 Android 应用程序是否从应用程序活动历史记录或启动器恢复
- python - 如何在 PyQt5 中使用带有 resource_path 的 PyInstaller --onefile 选项通过样式表添加图标?
- mariadb - 声明游标的正确方法是什么?
- hyperledger-fabric - 如何组织超级账本 fabrik 网络的节点?
- c# - 如何使用 ef 核心处理多个迁移提供者(SQLite、AzureSQL)?
- python - 带有过滤器的 Python SqlAlchemy 模型实例返回无类型
- python - 在数组中执行正则表达式搜索时,它返回为空
- c++ - 查找和处理 std::variants 列表中的替代项
- javascript - 在reactjs中的2个对象之间创建关系(OnetToMany)