2016-12-11 2 views
1

Предполагая, что у меня есть некоторый struct:C# Тип Значение параметра копия потокобезопасность

struct Foo{} 

, который был выделен в куче (как class члена), и у меня есть количество потоков, которые читать и писать это struct. Если я передать переменный в определенную функцию:

void Bar(Foo param); 

пары будут копией этого struct. Является ли сама операция копирования потоком безопасной?

ответ

0

Никогда не предполагайте, что какая-либо операция по потоку по умолчанию - так как это не так.

Для примера рассмотрим следующую Types:

public class A 
{ 
    public B b; 
} 

public struct B 
{ 
    public int a; 
    public int b; 
    public int c; 
    public int d; 
} 

и следующий метод:

public static void Func(B b) 
{ 
    Console.WriteLine($"{b.a}, {b.b}, {b.c}, {b.d}"); 
} 

Если вы будете иметь следующий Main метод и паузы консоли один раз в то время:

A a = new A(); 
new Thread(() => 
{ 
    while (true) 
    { 
     a.b.a = 5; 
     a.b.b = 5; 
     a.b.c = 5; 
     a.b.d = 5; 
    } 
}).Start(); 
while (true) 
{ 
    a.b.a = 1; 
    a.b.b = 2; 
    a.b.c = 3; 
    a.b.d = 4; 
    Func(a.b); 
} 

вы увидите, что некоторые из structs смешиваются между 1, 2, 3, 4 и 5.

Любое примитивное действие на типе более 32 бит не является атомарным на машине x86, то же, что и на 64 бит и x64.

Не то, что это означает, что вы можете использовать любую операцию на int будет безопасным, например:

манипулируя int от многоядерного процессора, скажем, ++someInt от 2-х потоков, даже если он компилирует incx86 инструкция может случиться.

  • someInt является 9.
  • сердечник 1 принимает someInt из своего кэша.
  • core 2 принимает someInt из кеша.
  • Ядро 1 увеличивает значение, которое оно имеет до 10, и сохраняет его в кеш.
  • Ядро 2 увеличивает значение, которое оно имеет до 10, и сохраняет его в кеш.

someInt был увеличен в два раза, но это равняется 10.

Использование Interlocked вместо, например, будет компилировать lock inc, который заблокирует шину и убедитесь, что ядро ​​имеет исключительное право собственности соответствующего кэша.

+1

Downvoter, пожалуйста, объясните, чтобы я мог улучшить свой ответ. –

+0

Согласен. У меня тоже нет ни одного аргумента. Возможно, мы ошибаемся, но это нужно уточнить. –

0

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

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

Например, загрузка long не является потокобезопасной, поскольку на 32-битной машине другой поток может записать ее, а затем вы прочтете половину старого значения и еще одну половину нового значения.

Все это означает, что структуры также занимают более 4 байтов.

+0

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

+0

И наоборот, даже 32-разрядные копии не являются потокобезопасными, если не 32-разрядными, но это никогда не будет применяться к копиям параметров. –

+0

Предполагается, что код будет скомпилирован как 64-разрядный. Поскольку это контролируется коммутатором компилятора, я бы не рекомендовал полагаться на него. –

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

  • Нет связанных вопросов^_^