2013-05-09 2 views
5

(Примечание: Я уже задавал этот вопрос, но ответ был специфичным для Java, поэтому я задаю тот же вопрос для C# и .NET framework. Это не дубликат.)Неустранимые «флаги» потокобезопасны в C# /. NET?

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

public class SampleAsync 
{ 
    public SampleAsync() { } 

    private bool completed; 
    public void Start() 
    { 
     var worker = new BackgroundWorker(); 
     worker.DoWork += (sender, e) => { 
      //... do something on a different thread 
      completed = true; 
     }; 
     worker.RunWorkerAsync(); 
    } 

    public void Update() 
    { 
     if (!completed) return; 
     //... do something else 
    } 
} 

* Пользователь несет ответственность за то, чтобы Start вызывалась только один раз. Update называется везде и где угодно.

Я всегда предполагал, что это потокобезопасно в C#/.NET framework, потому что, хотя ничто не строго синхронизировано, я только установил completed в true. Как только будет наблюдаться true, он не будет сброшен до false. Он инициализируется значением false в конструкторе, который по определению является потокобезопасным (если вы не делаете в нем что-то глупое). Таким образом, безопасно ли использовать потоки с помощью несанкционированных флагов? (И если да, то это даже дает никаких преимуществ производительности?)

Благодарности

+2

Вам нужно 'volatile'. – SLaks

+0

В C#, а также Java? Это потокобезопасность в противном случае? – aboveyou00

+1

«Как только было замечено, что это правда» - это бит, который никогда не может произойти, если вы не используете 'volatile'. –

ответ

3

Ваш код поточно, потому что bool является атомарным типа.

MSDN:

Чтение и запись следующих типов данных являются атомарными: BOOL, голец, байт, SByte, короткие, USHORT, UINT, INT, поплавок, и ссылочные типы. В дополнение, чтение и запись типов перечислений с базовым типом в , предыдущий список также является атомарным. Считывание и запись других типов, , включая длинные, улоновые, двойные и десятичные, а также определяемые пользователем типы , не гарантируются как атомарные. Помимо библиотеки функций, предназначенных для этой цели, нет гарантии атома read-modify-write, например, в случае приращения или уменьшения.

См: http://msdn.microsoft.com/en-us/library/aa691278(v=vs.71).aspx

Пожалуйста, отметьте ваше поле с volatile:

private volatile bool completed; 

MSDN:

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

См: http://msdn.microsoft.com/en-us/library/x13ttww7(v=vs.71).aspx

+0

... но все ставки отключены, если вы явно выровняете поле, используя '[FieldOffset]' или '[StructLayout]'. См. [Этот вопрос] (http://stackoverflow.com/q/15249626/146622). – Virtlink

+1

Означает ли это, что запись в это поле распространяется на другой поток (нити)? Я так не думаю. Значение может быть зарегистрировано. – usr

+0

@usr: Что значит «распространяется на другие потоки»? –

3

Это сильно зависит от целевой архитектуры. У процессоров Intel есть сильная модель памяти, поэтому вы, как правило, избегаете кода. Но тогда дрожь может сильно вас повредить. Например, джиттер x86 может хранить переменную в регистре процессора, особенно когда оператор if() отображается в узком цикле. И это делается только в выпуске Release, потрясающем отладочном кошмаре. Объявление переменной volatile является полосой для этого. Для джиттера x64 это не требуется, по крайней мере, в его текущей версии.Но band-aids, как правило, не останавливают кровотечение на процессорах со слабой моделью памяти, такой как ARM и Itanium. Они, конечно же, не обещают, что обновленное состояние переменной будет видимо в другом потоке в ближайшее время. Планировщик потоков стремится к сбросу кэша процессора. В итоге.

Нет смысла делать это неправильно. Используйте подходящий объект синхронизации, например AutoResetEvent. Или Interlocked.CompareExchange(), если вы беспокоитесь о циклах.

+0

Гарантирует ли volatile, что поле непосредственно хранится и всегда загружается из памяти? (Оба свойства необходимы для выполнения этой работы). Я не понимаю, на что гарантированно гарантируется волатильность. – usr

+0

@usr: Вам также нужно другое свойство - это не написано рано или спекулятивно. –

+2

+1 Ваш последний абзац подводит итог. Вам не нужно спрашивать, есть ли что-то потокобезопасное. Используйте объект синхронизации и * know *. –

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