Вопрос о многопоточности - добавление Элемента к статическому Списку

Да, добавление Вашего собственного Заметного Набора было бы достаточно справедливо. Не забывайте генерировать соответствующие события независимо, используется ли это UI в настоящий момент или нет;) необходимо будет повысить уведомление об изменении свойства для свойства "Item []" (требуемый стороной WPF и связанными элементами управления), а также NotifyCollectionChangedEventArgs с рядом добавленных объектов (диапазон). Я имею, сделал такие вещи (а также сортирующий поддержку и некоторый другой материал) и не имел никаких проблем с обоими уровнями Presentation и Code Behind.

5
задан Michael Stum 29 August 2009 в 18:40
поделиться

4 ответа

Вы обязательно должны заблокировать _list. И поскольку вы создаете несколько экземпляров для _list, вы не можете заблокировать сам _list, но вам следует использовать что-то вроде:

private static object _listLock = new object();

В качестве альтернативы, чтобы следовать нескольким передовым методам:

  • DoSomething () , как показано, может быть статическим, и так и должно быть.

  • для классов библиотеки рекомендуется сделать статические члены потокобезопасными, что будет применяться к StartRecording () , StopRecording () и DoSomething () .

Я бы также сделал StopRecording () set _list = null и проверил его на ноль в DoSomething () .

И прежде чем вы спросите, все это занимает так мало времени, что на самом деле нет причин , не , чтобы сделать это.

3
ответ дан 14 December 2019 в 01:12
поделиться

Вам нужно заблокировать список, если к нему добавляются несколько потоков.

Несколько наблюдений ...

Может быть, есть причина не делать этого, но я бы посоветовал создать класс static и, следовательно, все его члены static. Нет реальной причины, по крайней мере из того, что вы показали, требовать, чтобы клиенты MyClass вызывали метод GetInstance () только для того, чтобы они могли вызвать метод экземпляра, DoSomething () в этом случае.

Я не вижу что мешает кому-либо вызывать метод StartRecording () несколько раз. Вы могли бы подумать о том, чтобы поставить там отметку, чтобы, если он уже записывается, вы не создавали новый список, отрывая ковер от всех.

Наконец, когда вы блокируете список, не делайте этого так :

static object _sync = new object();
lock(_sync){
    _list.Add(new object(somedata));
}

Минимизируйте время, проводимое внутри блокировки, перемещая создание нового объекта за пределы блокировки.

static object _sync = new object();
object data = new object(somedata);
lock(_sync){
    _list.Add(data);
}

EDIT

Вы сказали, что DoSomething () не может быть статичным, но я уверен, что может. Вы по-прежнему можете использовать объект MyClass внутри DoSomething () для любых вещей, связанных с экземпляром, которые вам нужно сделать. Но с точки зрения удобства программирования не требуется, чтобы пользователи MyClass сначала вызывали GetInstance (). Примите во внимание следующее:

class MyClass {
    private static MyClass _instance;
    private static List<string> _list;
    private static bool IsRecording;
    public static void StartRecording()
    {
        _list = new List<string>();
        IsRecording = true;
    }
    public static IEnumerable<string> StopRecording()
    {
        IsRecording = false;
        return new List<string>(_list).AsReadOnly();
    }
    private static MyClass GetInstance() // make this private, not public
    {   return _instance;    }
    public static void DoSomething()
    {
        // use inst internally to the function to get access to instance variables
        MyClass inst = GetInstance();
    }
}

Таким образом, пользователи MyClass могут перейти с

MyClass.GetInstance().DoSomething();

на

MyClass.DoSomething();
3
ответ дан 14 December 2019 в 01:12
поделиться

Коллекции .NET не являются полностью потокобезопасными. Из MSDN : «Несколько читателей могут с уверенностью читать коллекцию; однако любое изменение коллекции приводит к неопределенным результатам для всех потоков, которые обращаются к коллекции, включая потоки читателей». Вы можете следовать предложениям на этой странице MSDN, чтобы сделать ваш доступ потокобезопасным.

Одна проблема, с которой вы, вероятно, столкнетесь с вашим текущим кодом, - это вызов StopRecording, когда какой-то другой поток находится внутри DoSomething. Поскольку создание нового списка из существующего требует перечисления по нему, вы, скорее всего, столкнетесь со старой проблемой «Коллекция была изменена; операция перечисления может не выполняться».

Итог: практикуйте безопасную потоковую передачу!

2
ответ дан 14 December 2019 в 01:12
поделиться

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

1
ответ дан 14 December 2019 в 01:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: