线程新手,需要帮助使用后台工作者使静态变量线程安全

时间:2014-06-13 18:54:13

标签: c# .net multithreading thread-safety backgroundworker

正如标题所示,我对线程概念不熟悉,而且我正在学习。我正在研究一个程序,作为涉及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()方法在这些线程中正常运行?

1 个答案:

答案 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