2016-11-15 2 views
0

У нас есть код устаревшего кода, который проверяет безопасность потоков на нескольких классах. Недавнее обновление аппаратного обеспечения (от 2 до 4 ядер) представляет случайные сбои с исключением, обращающимся к элементу из списка <>.Единичные тесты тестирования безопасности потоков - Объект недоступен случайным образом

 [Test] 
     public void CheckThreadSafeInThreadPool() 
     { 
      Console.WriteLine("Initialised ThreadLocalDataContextStore..."); 
      var container = new ContextContainerTest(); 
      Console.WriteLine("Starting..."); 
      container.StartPool(); 
      while (container.ThreadNumber < 5) 
      { 
       Thread.Sleep(1000); 
      } 

      foreach (var message in container.Messages) 
      { 
       Console.WriteLine(message); 
       if (message.Contains("A supposedly new thread is able to see the old value")) 
       { 
        Assert.Fail("Thread leaked values - not thread safe"); 
       } 
      } 

      Console.WriteLine("Complete"); 

     } 




public class ContextContainerTest 
    { 
     private ThreadLocalDataContextStore store; 
     public int ThreadNumber; 
     public List<string> Messages; 

     public void StartPool() 
     { 
      Messages = new List<string>(); 

      store = new ThreadLocalDataContextStore(); 
      store.ClearContext(); 
      var msoContext = new MsoContext(); 
      msoContext.Principal = new GenericPrincipal(new GenericIdentity("0"), null); 
      store.StoreContext(msoContext); 

      for (var counter = 0; counter < 5; counter++) 
      { 
       Messages.Add(string.Format("Assigning work item {0}", counter)); 
       ThreadPool.QueueUserWorkItem(ExecuteMe, counter); 
      } 
     } 

     public void ExecuteMe(object input) 
     { 

      string hashCode = Thread.CurrentThread.GetHashCode().ToString(); 

      if (store.GetContext() == null || store.GetContext().Principal == null) 
      { 
       Messages.Add(string.Format("[{0}] A New Thread", hashCode)); 
       var msoContext = new MsoContext(); 
       msoContext.Principal = new GenericPrincipal(new GenericIdentity("2"), null); 
       store.StoreContext(msoContext); 
      } 
      else if (store.GetContext().Principal.Identity.Name == "1") 
      { 
       Messages.Add(string.Format("[{0}] Thread reused", hashCode)); 
      } 
      else 
      { 
       Messages.Add(string.Format("[{0}] A supposedly new thread is able to see the old value {1}" 
        , hashCode, store.GetContext().GetDiagnosticInformation())); 
      } 

      Messages.Add(string.Format("[{0}] Context at starting: {1}", hashCode, store.GetContext().GetDiagnosticInformation())); 
      store.GetContext().SetAsCurrent(new GenericPrincipal(new GenericIdentity("99"), null)); 
      Messages.Add(string.Format("[{0}] Context at End: {1}", hashCode, store.GetContext().GetDiagnosticInformation())); 
      store.GetContext().SetAsCurrent(new GenericPrincipal(new GenericIdentity("1"), null)); 

      Thread.Sleep(80); 
      ThreadNumber++; 
     } 


    } 

Сбой случайный и встречается в следующем разделе кода внутри самого теста;

 foreach (var message in container.Messages) 
     { 
      Console.WriteLine(message); 
      if (message.Contains("A supposedly new thread is able to see the old value")) 
      { 
       Assert.Fail("Thread leaked values - not thread safe"); 
      } 
     } 

тонкое изменение решает проблему, но кто-то мелочный, что мы не должны делать это, почему это сообщение ноль, если сообщение не является, и почему она работает большую часть времени, а не другие.

if (message != null && message.Contains("A supposedly new thread is able to see the old value")) 
{ 
} 

Другим решением было изменить список потокобезопасны, но то не ответить, почему этот вопрос возник в первую очередь.

+1

Это не похоже на единичный тест - это не просто, не понятно, похоже, не проверяет только одно и имеет сложную логику установки. Преобразуйте свой список в класс потокобезопасности или используйте блокировки при доступе к списку - это, скорее всего, какое-то состояние гонки. Вы потратили гораздо больше времени на ввод этого вопроса, чем просто изменение кода для использования правильных структур данных в многопоточной среде. Кроме того, просто удалите этот тест - он плохо пахнет. – oleksii

+0

«Еще одно решение заключалось в том, чтобы сменить Список на потокобезопасность, но это не отвечает на то, почему проблема возникла в первую очередь», но проблема в том, что List не является потокобезопасным, какая еще причина вам нужна? – Evk

ответ

1

List<T> не является потокобезопасным элементом, если вы используете .Net 4 и выше, вы можете использовать ConcurrentBag<T> от System.Collection.Concurrent, а если старше, вы должны реализовать его самостоятельно. См. this может помочь.

Надеюсь, что я был полезным.

 Смежные вопросы

  • Нет связанных вопросов^_^