gpt4 book ai didi

c# - 同步访问由定时器重置的状态变量

转载 作者:行者123 更新时间:2023-11-30 22:22:55 25 4
gpt4 key购买 nike

我目前正在使用 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 是有效的(即允许延长状态为真的时间段),我可以想象单个锁可能不够用的情况。我想到的具体案例是这样的

  • 同时进入SetState和ResetState,分别在主线程和Timer线程
  • SetState先获取锁并正确设置state为true并触发定时器再次启动
  • ResetState 然后错误地将 state 设置为 false,这意味着 state 在预期的时间段内不为真

我已经为这个问题摸不着头脑了一会儿。我最接近能够解决它的方法是使用两个锁,但最后我发现这导致了其他问题(至少,我这样做的方式)。

是否有已知的方法来解决这个问题(我应该阅读一些东西来刷新我对同步的了解)吗?

更新:我忘了提到在这种情况下无法查询计时器的当前状态。如果可以的话,我会想象检查 ResetState 中的剩余时间以确定计时器是否真的停止了。

最佳答案

首先也是最重要的: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 方法,您将需要两个重置方法(定时器将使用私有(private)方法)。

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);
}

事情应该大致按照这些思路进行。

关于c# - 同步访问由定时器重置的状态变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13569569/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com