Threadsafe属性

时间:2013-11-15 22:44:23

标签: c# multithreading

我正在尝试学习C#上的线程,但是对于如何处理属性却有点困惑。

以我的班级NavigateIE为例,它一次只能执行一个动作。我想如果我有一个属性忙,那么我会知道实例是否在课堂外忙碌。

class NavigateIE
{
    public bool busy;

    public void IEAction(string action)
    {
        busy = true;

        var th = new Thread(() =>
                {
                    try
                    {
                        //Do stuff

                    }
                    catch(Exception ex)
                    {
                        //report Exception
                    }
                    finally
                    {
                        busy = false;
                    }
                });
        th.SetApartmentState(ApartmentState.STA);
        th.Start();

    }

}

但是,由于busy = false;只在线程中被调用,因此这不起作用,因为navigateIE.busy始终为true。

class MainElsewhere
{
    private NavigateIE navigateIE = new NavigateIE();

    private void Main()
    {
     if (!navigateIE.busy)
     {
      //navigateIE.busy always == true
     }
    }

}

我有两个问题:

1)如何设置属性以使其线程安全并且在课堂外看到busy = false;

2)有更好的方法吗?

编辑:本质上NavigateIE是一个使用Watin处理IE的单个实例的类。我只能在NavigateIE中调用一个方法,如果没有其他方法运行其他方法,则前一个操作尚未完成。 NavigateIE是从一个计时器滴答的主方法调用的,因此我需要检查该类是否正忙。

第一次

navigateIE.busy == false但是在线程将其设置为false之后,main方法仍然看到navigateIE.busy == true。

3 个答案:

答案 0 :(得分:3)

你这样做是根本错误的。是的, busy 很可能是真的,该线程将在现代多核处理器上快速开始运行。没有实际的保证,它只是非常普遍。当它转回 false 的时候也是高度不可预测的,取决于线程的作用。包括 never ,bool不是同步原语。

我不清楚你想要实现什么,但实际上你根本不需要使用忙碌的旗帜。 IE是一个单元线程的COM对象,它已经自动将调用封送到拥有该对象的STA线程。从另一个线程调用它的Navigate()方法很好,不需要额外的代码来帮助。如果您需要一个忙标志来指示浏览器正在处理命令,那么您需要一个在实际开始导航时设置为true的标志,而不是在启动线程时。可能会利用this answer中的代码。

答案 1 :(得分:2)

我开始写一个答案,但这里有很多变数。 (你应该锁定,但真正的信号可能是更好的解决方案等)。我真的认为,不是向你扔一个代码片段,更好的答案是指导你多做一点.net线程。

这是一本可能对您有所帮助的电子书:http://www.albahari.com/threading/

答案 2 :(得分:2)

  1.   

    如何设置属性以便在课堂外看到[..] busy = false;

    您的示例无效,因为busy需要标记为volatile

  2.   

    有更好的方法吗?

    听起来NavigateIE 中的所有呼叫始终需要序列化。如果这是真的,我会在每个线程调用

    中放一个lock语句
    public object mutex = new object();
    
    public void IEAction(string action)
    {
         var th = new Thread(() =>
            {
                lock(mutex)
                {
                    //Serialzed code goes here
                }
            });
    
         //etc.
    }
    

    另外,请注意,您很少想要实际创建自己的Thread实例 - 您应该使用BackgroundWorker,从ThreadPool获取线程,或使用新{ {3}}

    如果您不确定,TPL通常是最好的起点。