C # Является ли присвоение типа значения атомарным? - PullRequest
0 голосов
/ 03 декабря 2018

Является ли присвоение типа значения атомарным в .Net?

Например, рассмотрим следующую программу:

struct Vector3
{
    public float X { get; private set; }
    public float Y { get; private set; }
    public float Z { get; private set; }


    public Vector3(float x, float y, float z)
    {
        this.X = x;
        this.Y = y;
        this.Z = z;
    }

    public Vector3 Clone()
    {
        return new Vector3(X, Y, Z);
    }

    public override String ToString()
    {
        return "(" + X + "," + Y + "," + Z + ")";
    }
}

class Program
{
    private static Vector3 pos = new Vector3(0,0,0);

    private static void ReaderThread()
    {
        for (int i = 0; i < int.MaxValue; i++)
        {
            Vector3 v = pos;
            Console.WriteLine(v.ToString());
            Thread.Sleep(200);
        }

    }

    private static void WriterThread()
    {
        for (int i = 1; i < int.MaxValue; i++)
        {
            pos = new Vector3(i, i, i);
            Thread.Sleep(200);
        }
    }


    static void Main(string[] args)
    {
        Thread w = new Thread(WriterThread);
        Thread r = new Thread(ReaderThread);

        w.Start();
        r.Start();
    }
}

Может ли такая программа страдать от High-Level гонка данных?Или даже Data Race ?

Что я хочу знать здесь: есть ли вероятность, что v будет содержать:

  • Значения мусора из-завозможная гонка данных
  • Смешанные компоненты X, Y или Z, которые относятся как к положению до назначения, так и к положению после назначения.Например, если pos = (1,1,1) и затем ему присвоено новое значение (2,2,2), может v = (1,2,2)?

1 Ответ

0 голосов
/ 04 декабря 2018

Структуры являются типами значений.Если вы присвоите структуру переменной / полю / параметру метода, все содержимое структуры будет скопировано из исходного хранилища в место хранения параметра переменной / поля / метода (место хранения в каждом случае равно размерусама структура).

Копирование структуры не обязательно является атомарной операцией.Как написано в спецификации языка C # :

атомарность ссылок на переменные

Чтения и записи следующих типов данных являются атомарными: bool , char , byte , sbyte , short , ushort , uint , int , float и ссылочные типы .Кроме того, чтение и запись перечислимых типов с базовым типом в предыдущем списке также являются атомарными.Чтение и запись других типов, включая long , ulong , double и decimal , а также определяемые пользователем типыне гарантированно быть атомным.Помимо функций библиотеки, разработанных для этой цели, нет гарантии атомарного чтения-изменения-записи, например, в случае увеличения или уменьшения.

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


В качестве примечания, ваш код также может страдать от других проблем параллелизма из-за того, как один из ваших потоковпишет в переменную и как переменная используется другим потоком.(Ответ пользователя acelent на другой вопрос объясняет это довольно хорошо с технической точки зрения, поэтому я просто на него ссылаюсь: https://stackoverflow.com/a/46695456/2819245) Вы можете избежать таких проблем, инкапсулируя любой доступ к такой "ветке"Перекрестные переменные в блоке lock. В качестве альтернативы lock и в отношении базовых типов данных вы также можете использовать методы, предоставляемые классом Interlocked, для доступа к переменным / полям, пересекающим поток, в потоке.-обезопасный способ (хотя чередование методов lock и Interlocked для одной и той же переменной пересечения потока не очень хорошая идея).

...