我正在尝试学习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。
答案 0 :(得分:3)
你这样做是根本错误的。是的, busy 很可能是真的,该线程将在现代多核处理器上快速开始运行。没有实际的保证,它只是非常普遍。当它转回 false 的时候也是高度不可预测的,取决于线程的作用。包括 never ,bool不是同步原语。
我不清楚你想要实现什么,但实际上你根本不需要使用忙碌的旗帜。 IE是一个单元线程的COM对象,它已经自动将调用封送到拥有该对象的STA线程。从另一个线程调用它的Navigate()方法很好,不需要额外的代码来帮助。如果您需要一个忙标志来指示浏览器正在处理命令,那么您需要一个在实际开始导航时设置为true的标志,而不是在启动线程时。可能会利用this answer中的代码。
答案 1 :(得分:2)
我开始写一个答案,但这里有很多变数。 (你应该锁定,但真正的信号可能是更好的解决方案等)。我真的认为,不是向你扔一个代码片段,更好的答案是指导你多做一点.net线程。
这是一本可能对您有所帮助的电子书:http://www.albahari.com/threading/
答案 2 :(得分:2)
如何设置属性以便在课堂外看到[..]
busy = false;
?
您的示例无效,因为busy
需要标记为volatile
有更好的方法吗?
听起来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通常是最好的起点。