C # структурирует потокобезопасность? - PullRequest
8 голосов
/ 01 марта 2010

Является ли структура C # поточно-безопасной?

Например, если есть:

struct Data
{
    int _number;
    public int Number { get { return _number; } set { _number = value; } }

    public Data(int number) { _number = number; }
}

в другом типе:

class DadData
{
    public Data TheData { get; set; }
}

это свойство с именем TheData, поточно-ориентированное?

Ответы [ 6 ]

9 голосов
/ 01 марта 2010

Что ж, лучшая практика заключается в том, что структуры должны всегда (за исключением нескольких очень специфических сценариев и даже в случае риска) быть неизменными. И неизменные данные всегда безопасны для потоков. Итак, если вы следовали лучшей практике и сделали это:

struct Data
{
    readonly int _number;
    public int Number { get { return _number; } }

    public Data(int number) { _number = number; }
}

тогда да; это потокобезопасно. Во всех остальных случаях ответ «вероятно, нет».

Обратите внимание, что применяются правила атомарности, поэтому нельзя даже считать, что одно чтение или обновление до DadData.TheData является поточно-ориентированным, даже с неизменной структурой. Вы можете (особенно для негабаритных структур) иметь один поток, читающий структуру, в то время как другой поток переписывает ее; без синхронизации будут происходить плохие вещи (со временем).

8 голосов
/ 01 марта 2010

Нет, структуры в .NET не являются поточно-ориентированными.

Однако семантика копирования по значению в этих структурах имеет большое значение для этой конвекции.

Если вы передаете свои структуры и присваиваете их каким-либо образом переменным или параметрам передачи по значению (без ключевых слов ref или out), тогда используется копия .

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

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

1 голос
/ 01 марта 2010

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

Кроме того, изменяемые структуры являются запахами кода. Есть ли какая-то особая причина, по которой вам нужно, чтобы он был struct вместо class? Вам нужна семантика типа значения для этих данных?

0 голосов
/ 15 мая 2015

Нет, это не так. Я создал очень простое приложение, чтобы увидеть, обращаются ли потоки 10/10 / производителя к одной и той же переменной структуры. И в конце концов вы увидите Debugger.Break (); будет поражен. Баланс банка никогда не должен превышать 0.

namespace StructThreadSafe
{
    class Program
    {
        struct BankBalance
        {
            public decimal Balance { get; set; }
        }

        static void Main(string[] args)
        {
            BankBalance bankBalance = new BankBalance();
            bankBalance.Balance = 100;
            List<Task> allTasks = new List<Task>();
            for (int q = 0; q < 10; q++)
            {
                Task producer = new Task(() =>
                {
                    for (int i = 0; i < 1000; i++)
                    {
                        if (bankBalance.Balance < 0)
                        {
                            if (Debugger.IsAttached)
                            {
                                Debugger.Break();
                            }   
                        }
                        bankBalance.Balance += 5;
                        Console.WriteLine("++Current Balance: " + bankBalance.Balance);
                        System.Threading.Thread.Sleep(100);
                    }
                });
                allTasks.Add(producer);
            }
            for (int w = 0; w < 10; w++)
            {
                Task consumer = new Task(() =>
                {
                    for (int i = 0; i < 1000; i++)
                    {
                        if (bankBalance.Balance < 0)
                        {
                            if (Debugger.IsAttached)
                            {
                                Debugger.Break();
                            }
                        }
                        if (bankBalance.Balance > 15)
                        {
                            bankBalance.Balance -= 15;
                            Console.WriteLine("--Current Balance: " + bankBalance.Balance);
                        }
                        else
                        {
                            Console.WriteLine("**Current Balance below minimum: " + bankBalance.Balance);
                        }
                        System.Threading.Thread.Sleep(100);
                    }
                });
                allTasks.Add(consumer);
            }
            allTasks.ForEach(p => p.Start());
            Task.WaitAll(allTasks.ToArray());

        }
    }
}
0 голосов
/ 07 февраля 2012

Прямое чтение и запись в разные потоки разных членов изменяемой структуры не будет мешать друг другу. Доступ разных потоков к одному и тому же члену через методы Interlocked будет вести себя в соответствии с семантикой этих методов. Эти факты могут позволить изменчивым структурам разрешить поточно-ориентированное поведение.

Изменяемые области хранения, содержащие структуры, которые не предлагают никаких средств мутации, кроме прямой замены, не обеспечивают никакой безопасности потока, за исключением того, что в случаях, когда структура содержит либо одно 32-битное целое число, либо ссылку на один объект, попытка прочитать такое (одноэлементное) хранилище структур в одно и то же время, когда оно записывается, гарантирует чтение полностью старых или совершенно новых данных. Обратите внимание, что невозможно использовать любые методы Interlocked с неизменяемыми структурами - даже структуры, которые содержат только одно целое число или ссылку на объект.

0 голосов
/ 01 марта 2010

Нет. Почему это будет потокобезопасным? Это просто данные. Это не становится потокобезопасным от магии.

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