我目前正在使用C#开展项目。我正在使用单个锁同步访问状态变量。触发此状态变量以在给定的时间段内设置,然后应重置其值。我目前的代码如下。
using System.Threading;
class Test
{
object syncObj = new object();
bool state = false;
Timer stateTimer;
Test()
{
stateTimer = new Timer(ResetState, this, Timeout.Infinite, Timeout.Infinite);
}
void SetState()
{
lock(syncObj)
{
state = true;
stateTimer.Change(1000, Timeout.Infinite);
}
}
static void ResetState(object o)
{
Test t = o as Test;
lock(t.syncObj)
{
t.state = false;
}
}
}
假定在Timer调用ResetState之前再次调用SetState是有效的(即允许延长状态为true的时间段),我可以想象单个锁可能不够的情况。我正在考虑的具体案例是
我一直在摸着这个。我能够解决它的最接近的是使用两个锁,但最后我发现这导致了其他问题(至少,我做的方式)。
有没有一种已知的方法来解决这个问题(我应该阅读一些东西来刷新我的同步知识)?
更新:我忘了提到在这种情况下无法查询定时器的当前状态。如果可以的话,我会想象在ResetState中检查剩余时间以确定计时器是否真的停止了。
答案 0 :(得分:3)
首先:it's a bad idea to expose the locking object publicly!
class Test
{
private object syncObj = new object();
private bool state = false;
private Timer stateTimer;
public Test()
{
stateTimer = new Timer(ResetState, this, Timeout.Infinite, Timeout.Infinite);
}
public void SetState()
{
lock(syncObj)
{
state = true;
stateTimer.Change(1000, Timeout.Infinite);
}
}
public static void ResetState(object o)
{
Test t = o as Test;
t.ResetState();
}
由于您不再暴露锁定对象,因此您必须创建另一种方法来重置状态:
public void ResetState()
{
lock(syncObj)
{
state = false;
stateTimer.Change(Timeout.Infinite, Timeout.Infinite);
}
}
}
请注意,我们还会处理新ResetState
方法中的另一个问题,那就是强制计时器不要再次触发。这只能保证state
标志不会与定时器不同步;即,如果您设置状态,它将保持设置预期的时间量或直到调用重置方法。
如果要拒绝重置尝试,请将状态变量设为枚举:
enum EState
{
Off = 0,
On = 1,
Waiting = 2
}
private EState state = EState.Off;
// Provide a state property to check if the state is on or of (waiting is considered to be Off)
public bool State{ get{ return state == EState.On;} }
此外,您现在需要修改SetState方法,您将需要两个重置方法(私有方法将由计时器使用)。
public void SetState()
{
lock(syncObj)
{
state = EState.Waiting;
stateTimer.Change(1000, Timeout.Infinite);
}
}
public void ResetState()
{
lock(syncObj)
{
if(state != EState.Waiting)
{
state = EState.Off;
}
}
}
private void TimerResetState()
{
lock(syncObj)
{
state = EState.Off;
stateTimer.Change(Timeout.Infinite, Timeout.Infinite);
}
}
所以现在你的构造函数看起来像这样:
public Test()
{
stateTimer = new Timer(TimerResetState, this, Timeout.Infinite, Timeout.Infinite);
}
事情应该大致沿着这些方向发展。