2014-01-24 9 views
0

Я новичок в C#, но изучаю его. Я понял, что у C# есть много удивительных методов, таких как Parallel.Параллельно вызывает тупик?

Итак, скажем, моя программа имеет этот метод.

private void stackOverFlowExample() 
{ 
    List<string> testCompany = new List<string>(); 
    List<People> testList = new List<People>(); 

    testCompany.Add("Stack Over Flow 1"); 
    testCompany.Add("Stack Over Flow 2"); 
    testCompany.Add("Stack Over Flow 3"); 
    ...(1000 Times)... 

    Parallel.ForEach(testCompany, company => 
    { 
     testList.Add(new People() 
     { 
      Name = value1, // Some values 
      Address = value2, 
      Phone = value3, 
      Company = company 
     }); 
    }); 
} 

Значит, код выше имеет проблемы, связанные с резьбой? И есть ли какая-нибудь книга или руководство, связанное с решением проблем нитей, которые вы можете порекомендовать?

+3

В вашем коде нет блокировки, поэтому вы не увидите никаких взаимоблокировок, но вы получаете доступ к коллекции, которая не является потокобезопасной для нескольких потоков, поэтому поведение не определено. –

ответ

2

Этот код действительно есть проблемы, связанные нити, но не то, что бы можно назвать тупиком.

Проблема с кодом заключается в том, что несколько потоков будут добавлять элементы в список, но класс List<T> не является потокобезопасным, поэтому, если любой из потоков добавляет элементы одновременно, объект списка будет поврежден.

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

Для простого объяснения тупиков: How to explain the "deadlock" better?


Нить безопасный вариант кода будет использовать блокировку вокруг кода, который добавляет элемент в список, чтобы убедиться, что только один поток время составления кода:

private void stackOverFlowExample() 
{ 
    List<string> testCompany = new List<string>(); 
    List<People> testList = new List<People>(); 
    object sync = new Object(); 

    testCompany.Add("Stack Over Flow 1"); 
    testCompany.Add("Stack Over Flow 2"); 
    testCompany.Add("Stack Over Flow 3"); 
    ...(1000 Times)... 

    Parallel.ForEach(testCompany, company => 
    { 
     People p = new People() 
     { 
      Name = value1, // Some values 
      Address = value2, 
      Phone = value3, 
      Company = company 
     }; 
     lock (sync) { 
      testList.Add(p); 
     } 
    }); 
} 
0

Нет, взаимоблокировка связана с блокировкой, а не с параллельным программированием. Таким образом, в вашем коде может быть тупик, но он не будет напрямую связан с тем фактом, что вы используете Parallel.ForEach.

Пример тупика:

 object locker1 = new object(); 
     object locker2 = new object(); 

     new Thread (() => { 
       lock (locker1) 
       { 
        Thread.Sleep (1000); 
        lock (locker2); // Deadlock 
       } 
      }).Start(); 

     lock (locker2) 
     { 
      Thread.Sleep (1000); 
      lock (locker1); // Deadlock 
     } 

Я рекомендую вам прочитать мою последнюю запись в блоге о наиболее распространенных ошибках и ловушках при создании многопоточных приложений. : http://blog.goyello.com/2014/01/21/threading-in-c-7-things-you-should-always-remember-about/

В случае, если Вы хотели бы узнать больше о многопоточности в C# Я рекомендую вам прочитать эту бесплатную электронную книгу: http://www.albahari.info/threading/threading.pdf

1

Нет, для того, чтобы зайти в тупик, вам нужно как минимум два общих ресурса для блокировки. но если вы имеете в виду Потокобезопасного кода, то, вероятно, да, так как доступ к testList без какого-либо контроля со многими нитями ...

Для тупика, вы должны иметь что-то вроде этого

>Thread1 
lock(a) 
    lock(b) 
    DoSomething1() 


>Thread2 
lock(b) 
    lock(a) 
    DoSomething2() 
Смежные вопросы