正如标题所示,我对线程概念不熟悉,而且我正在学习。我正在研究一个程序,作为涉及3D打印机的研究项目的一部分。我有两个需要连接的硬件:一个上下移动的小舞台,一个力传感器,可以检测舞台上的物体何时与传感器接触,作为停止移动舞台的信号。正如我所说,我是整个线程概念的新手,所以我甚至不确定我是否正确设计,如果我应该使用backgroundworker或Thread类,如何确保线程安全等等。
我正在使用Windows Forms在C#中编写程序,并决定在Visual Studio / .NET Framework中使用两个后台工作程序控件,一个用于监视力传感器读数,另一个用于控制舞台上下移动。 / p>
必须快速准确;当检测到预定义的传感器值时,该阶段需要停止移动。我有两个静态类,一个ZStageControl静态类和一个ForceSensorControl静态类。
ForceSensorControl有一个名为UpdateSensor()的方法,它返回力传感器的当前值,ZStageControl有一个私有静态bool变量forceDetected(默认设置为false),一个获取/设置此变量的公共属性ForceDetected ,以及一个名为GoodToMove的方法。 GoodToMove的定义如下:
public static bool GoodToMove()
{
if (forceDetected == true ||
Position() < MinHeight ||
Position() > MaxHeight)
return false;
else
return true;
}
我的传感器更新后台工作程序dowork代码定义如下:
private void sensorUpdateBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
double currentForceValue;
while (ForceSensorControl.IsConnected() == true)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
try
{
currentForceValue = Double.Parse(ForceSensorControl.UpdateSensor());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
disconnectForceSensor();
return;
}
if (currentForceValue >= forceSensorStopValue)
{
if (this.ForceDetected != null)
{
this.ForceDetected(this,
new ForceDetectedEventArgs(ZStageControl.Position(), currentForceValue));
}
}
else if (ZStageControl.ForceDetected == true)
ZStageControl.ForceDetected = false;
forceSensorValueLabel.Text = currentForceValue.ToString() + "g";
}
}
}
只要传感器保持连接,就会不断循环并更新力传感器。如果它检测到正确的力值,则会触发ForceDetected事件。如果它读取的值小于力传感器停止值,但ForceDetected仍然设置为true,则它只是设置为false(因为当检测到力时,它将停止移动阶段然后将其返回到其默认位置,所以它应该重置检测到的力变量)。
事件代码定义如下:
public void FormMain_ForceDetected(object sender, ForceDetectedEventArgs e)
{
if (ZStageControl.ForceDetected == true)
return;
ZStageControl.ForceDetected = true;
feedbackRichTextBox.Text += "\nForce Detected at position " +
e.ForceDetectedPosition.ToString() + " with a value of " +
e.ForceDetectedValue.ToString() + "\n";
ScrollToEndOfFeedbackBox(feedbackRichTextBox);
soundPlayer.Play();
}
向上或向下移动Z-Stage的线程定义如下:
private void zStageMoveBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
ZStageMoveDirections direction = (ZStageMoveDirections)e.Argument;
while (ZStageControl.IsConnected == true)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
System.Threading.Thread.Sleep(zStageSpeed);
if (direction == ZStageMoveDirections.Down)
{
ZStageControl.MoveDown(true);
}
if (direction == ZStageMoveDirections.Up)
{
ZStageControl.MoveUp(true);
}
zStagePositionUpdateLabel.Text = ZStageControl.Position().ToString();
}
}
}
调用Z-Stage移动的DoWork事件的代码由if语句控制,该语句检查ZStageControl.GoodToMove()是否为true。因此,当GoodToMove()返回true时,Z-Stage线程可以触发。
我遇到的问题是,我不确定我是否正在设计这个,如果我正确使用了背景工作者,并且我知道我的变量不是线程安全的,因为在某些点GoodToMove()返回true,其他时间返回false,即使显然没有检测到力。它似乎有自己的想法。我对线程安全一无所知。我应该只使用THread类而不是后台worker,是否有某种方法可以确保forceDetected变量/ GoodToMove()方法在这些线程中正常运行?
答案 0 :(得分:2)
我认为你的做法存在固有的缺陷。
您似乎正在设计一个带有不断循环监视器的系统,然后在您想要执行&#34;移动时检查该监视器。&#34;
这本质上是有问题的,因为您在安全检查操作和移动操作之间造成了竞争条件。
考虑一下:
1 // check if move is ok -- PASS
(async) // move suddenly becomes not ok!
2 // move is executed
相反,您应该将此问题视为完全同步(因为验证检查和执行应完全是原子的)。每当请求移动时,您应检查是否允许移动,然后决定是否执行。
1 // exclusive lock
2 // check if move is ok -- PASS
3 // execute move
4 // release lock