Этот поток кода и синхронизация безопасны? - PullRequest
1 голос
/ 13 октября 2010

Мне нужен токен аутентификации для обеспечения безопасности потока и синхронизации. Срок действия токена истекает каждый час, поэтому необходимо будет создать новый и присвоить его моей статической переменной (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 Ответ

4 голосов
/ 13 октября 2010

Нет, этот код не является потокобезопасным. Поскольку блокировка происходит внутри операторов if, два потока могут создать токен примерно в одно и то же время. Учтите следующее:

  • Тема 1 входит else блок
  • Тема 1 уступает теме 2
  • поток 2 входит else блок
  • Поток 2 блокирует syncRoot, создает новый токен (токен A) и назначает его на TOKEN
  • Поток 2 возвращает "токен A".
  • Поток 2 уступает потоку 1
  • Поток 1 блокирует syncRoot, создает новый токен (токен B) и назначает его TOKEN
  • Поток 1 возвращает "токен B".

Ваша система теперь использует два разных токена, которые были созданы только на расстоянии нескольких секунд, и Thread ссылается на "токен B".

Edit:
Вы можете сделать свой поток безопасным, взяв блокировку еще до проверки токена. Приведенный ниже пример блокирует каждый вызов Get(), поэтому он не будет создавать два токена одновременно (почти) одновременно с вашим кодом. Вы также можете использовать другие схемы блокировки, некоторые из которых могут повысить производительность.

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