此代码线程和同步是否安全?

时间:2010-10-13 01:46:36

标签: c# thread-safety

我需要一个身份验证令牌才能保证线程和同步安全。令牌将每小时到期,因此需要创建一个新令牌并将其分配给我的静态变量(TOKEN)

这会起作用吗?

谢谢,

    public static volatile string TOKEN = string.Empty;
    public static DateTime TOKEN_TIME = DateTime.Now;
    private static readonly object syncRoot = new object(); 

    public static string Get()
    {
        if (!string.IsNullOrEmpty(TOKEN))
        {
            if (!TokenIsValid())
            {
                lock(syncRoot)
                    TOKEN = CreateNewToken();
            }                
        }
        else
        {
            lock(syncRoot)
                TOKEN = CreateNewToken();
        }

        return TOKEN;
    }         

1 个答案:

答案 0 :(得分:4)

不,该代码不是线程安全的。由于锁定发生在if语句内部,因此两个线程可能几乎同时创建一个令牌。请考虑以下事项:

  • 主题1进入else
  • 线程1产生线程2
  • 主题2进入else
  • 线程2锁定syncRoot,创建新令牌(令牌A),并将其分配给TOKEN
  • 线程2返回“令牌A”。
  • 线程2产生线程1
  • 线程1锁定syncRoot,创建新令牌(令牌B),并将其分配给TOKEN
  • 线程1返回“令牌B”。

您的系统现在使用两个不同时间间隔创建的令牌,Thread引用“令牌B”。

修改
在检查令牌之前,您可以通过锁定来使代码线程安全。下面的示例锁定了对Get()的每次调用,因此它不会像代码一样(几乎)同时创建两个令牌。您还可以使用其他锁定模式,其中一些可能会提供更好的性能。

public static string Get()
{
    lock(syncRoot)
    {
        if (string.IsNullOrEmpty(TOKEN) || !TokenIsValid())
            TOKEN = CreateNewToken();
        return TOKEN;
    }
}