Этот код потокобезопасен? - PullRequest
1 голос
/ 04 апреля 2010

У меня есть класс с несколькими свойствами. При каждом обновлении значения вызывается метод Store, который сохраняет все поля (в файле).

private int _Prop1;
public int Prop1 {
    get {
        return _Prop1;
    }
    set {
        _Prop1 = value;
        Store();
    }
}

// more similar properties here...

private XmlSerializer _Ser = new ...;
private void Store()
{
    lock (_Ser) {
        using (FileStream fs = new ...) {
            _Ser.Serialize (fs, this);
        }
    }
}

Является ли эта конструкция поточно-ориентированной?

(Кстати, если вы можете придумать более подходящую подпись, не стесняйтесь редактировать.)

Я думаю, что это потокобезопасно. Если свойства изменяются в нескольких потоках, значения будут установлены в случайном порядке, атомарные хранилища будут происходить в случайном порядке, но в конце каждое свойство будет иметь свое последнее значение, и в самом конце, атомарное хранилище происходит, обеспечение актуальности файла.

Уточнение: Свойства устанавливаются не очень часто, но могут задаваться одновременно. Главное, чтобы у вас был действительный файл большую часть времени.

Если поток собирается изменить свойство в отношении значения свойства, он должен заблокировать весь объект для синхронизации с другими потоками. Это в основном то же самое, что и при блокировке List при перечислении, и не входит в этот класс.

Ответы [ 6 ]

5 голосов
/ 04 апреля 2010

Это зависит от того, что вы вызываете в разных темах.

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

1 голос
/ 04 апреля 2010

Недостаточно кода для совершения звонка. Но, конечно, ничего хорошего не произойдет, если вы не сериализуете права на запись в файл. 2-й поток, который присваивает свойство, собирается запустить IOException, если 1-й поток все еще занят записью файла.

Такая мелкозернистая блокировка обычно является проблемой. Код клиента может быть занят изменением нескольких свойств класса. Вы получите частичное обновление, если возникнет исключение, создав файл, содержащий сериализованное состояние, которое недопустимо и может вызвать проблемы при чтении. Вам понадобится что-то вроде пары BeginUpdate (), EndUpdate ().

1 голос
/ 04 апреля 2010

номер

В случае, если вы хотите синхронизировать свойства сами, этот код не является потокобезопасным, поскольку «блокировка» не для значения _Prop1, а только для _Ser. Действительно, когда поток получает свойство, свойство может быть установлено другим потоком.

Даже процесс сериализации, _Ser доступ к свойствам, которые могут быть изменены другими выполняемыми потоками (пока _Ser работает, другой поток устанавливает Prop1).

Этот код фактически запрещает использование объекта XmlSerialize _Ser несколькими потоками. Если это то, что вы хотите получить ...


Ответ в основном зависит от того, что вы хотите получить.

0 голосов
/ 04 апреля 2010

Не потокобезопасен, если тип свойства не атомарный.

Простой пример, с потоками A и B.

A: Prop1 = foo
A: Store()
A:    ... store saves foo.Var1
B: Prop1 = bar
A:    ... store saves bar.Var2 (instead of foo.Var2)

Целостность данных может быть нарушена. Даже с такими простыми типами, как Int64, проблемы могут возникнуть в теории.

Помещение другого lock(_Ser) в сеттер поможет.

0 голосов
/ 04 апреля 2010

Если свойство Prop1 может быть вызвано из нескольких потоков, введите в поле _Prop1 volatile.

private volatile int _Prop1;

Из MSDN,

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

Считайте это хорошей практикой. Это не сделает код, который вы опубликовали, потокобезопасным, потому что, как говорили другие, во время сериализации класса значение _Prop1 может быть изменено другим потоком. Тем не менее, если у вас есть поле, которое может быть прочитано и записано несколькими потоками, пометка поля как изменяемого гарантирует, что ваш код увидит самое текущее значение.

0 голосов
/ 04 апреля 2010

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

Следующая ссылка приведет вас к простому примеру на веб-сайте MSDN, который, как мы надеемся, продемонстрирует вам:

Пример мьютекса

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...