2013-03-12 3 views
-1
private static Thread thread; 
private static List<object> items = new List<object>(); 

static Program() 
{ 
    thread = new Thread(() => 
     { 
     foreach (var item in items) 
     { 
      item.Name = "ABC"; 
     } 
     Thread.Sleep(3600); 
     }); 
    thread.Start(); 
} 

private static void Main(string[] args) 
{ 
    var item = items.Where(i => i.Name == "ABC").FirstOrDefault(); 
    if(item != null) 
     { 
     items.Remove(item); 
     } 

} 

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

, когда выполняется цикл внутри цикла foreach нового потока, и в то же время цикл foreach также выполняется, он выдает ошибку, которая не может изменить список.

Любая идея, как преодолеть проблему?

Благодаря

+5

Ваш код не изменяет список, когда-либо ... что ваш фактический код делает? –

+3

Вы не можете изменить список, если вы перечислите его, даже если вы не используете нити. – Matten

+0

Существует комментарий // Выполнение операции по элементу – BreakHead

ответ

-1

Вы уверены, что это Многопоточность вопрос? Список является relativly threadsafe, и методы добавления и удаления достаточно быстры (насколько я знаю), что MS не распознает его как проблему, в отличие от Queue и ConcurrentQueue

Обратите внимание, что вы не можете изменять коллекцию во время цикла через него, используя Еогеасп так

List<int> integers = new List<int>(new int[] { 1,2,3,4,5,}); 
foreach(int i in integers) 
    integers.Add(1); // Will throw an InvalidOperationException 
+1

«Список ** ** может поддерживать несколько считывателей одновременно, пока сбор не изменяется. Перечисление через коллекцию по сути не является потокобезопасной процедурой. В редком случае, когда перечисление содержит одну или несколько записей доступа, ** единственным способом обеспечения безопасности потоков является блокировка коллекции во время всего перечисления **. Чтобы обеспечить доступ к коллекции несколькими потоками для чтения и записи, вы должны реализовать свою собственную синхронизацию ». –

+1

Коррупция списка с помощью нескольких одновременных авторов - это игра для детей. Нет такой вещи, как «относительно потокобезопасная». Это похоже на «немного беременную». Либо он поддерживает несколько параллельных авторов, либо нет. –

+0

Если вы считаете, что добавление или удаление списка фактически потокобезопасны, вы совершенно ошибаетесь. Операции не очень быстры для больших списков, если вы не добавляете/не удаляете последний элемент в списке (в этом случае это будет очень быстро). Удаление первого элемента означает, что * каждый отдельный элемент в списке * необходимо перемещать на одну позицию. Если вы не видите, как это может иметь негативные последствия, или как это можно сделать так быстро, чтобы казаться атомарным, я предлагаю вам оставаться * далеко * от любого вида многопоточного программирования. – Servy

0

тема вы говорите о том, резьбонарезных

безопасность

Для достижения этой цели, вы должны использовать синхронизированные методы

Edit:

К сожалению о том, что один, конечно же C#, смотрите здесь: http://msdn.microsoft.com/en-us/library/ms173179.aspx

Это почти так же, как синхронизации в Java, вы просто должны зафиксировать объект на время вы работаете с ним, таким образом ваши темы оставаться в безопасности

Имейте в виду, что в то время как объект заблокирован, все другие потоки, пытающиеся получить доступ к объекту будет ждать, что может привести к тупиковой ситуации

+0

Речь идет о C#, а не java. Даже если понятия одинаковы, C# не знает о ключевом слове 'synchronized'. – Matten

0

в вашем примере вы не изменения коллекции в enumerati на. Однако вы изменяете сбор за пределами перечисления, и если это произойдет во время перечисления, вы получите исключение InvalidOperationException: Collection was modified.

MSDN От:

List (T) может поддерживать несколько читателей одновременно, до тех пор, как коллекция не изменяется. Перечисление через коллекцию по существу не является потокобезопасной процедурой. В редком случае, когда перечисление имеет один или несколько обращений на запись, единственный способ: обеспечить безопасность потока, чтобы заблокировать сбор в течение всего перечисления. Чтобы обеспечить доступ к коллекции несколькими потоками для чтения и записи, вы должны реализовать свою собственную синхронизацию .

private static Thread thread; 
private static List<object> items = new List<object>(); 
private Object theLock = new Object(); 

static Program() 
{ 
    thread = new Thread(() => 
    { 
     lock(theLock) 
     { 
     foreach (var item in items) 
     { 
      item.Name = "ABC"; 
     } 
     } 
     Thread.Sleep(3600); 
    }); 
    thread.Start(); 
} 

private static void Main(string[] args) 
{ 
    lock(theLock) 
    { 
    var item = items.Where(i => i.Name == "ABC").FirstOrDefault(); 
    if(item != null) 
    { 
     items.Remove(item); 
    } 
    } 
} 
Смежные вопросы