Под C# использование Int64 на опасном процессоре на 32 бита

В качестве обходного пути вы можете распространять стили своего контейнера между двумя различными контейнерами:

  • Внешний с размерами, границами и переполнением
  • Внутренний с стилями flexbox

Если вы хотите, чтобы по умолчанию она была прокручена вниз, вы можете использовать JS: Прокрутите вниз до div?

function scrollToBottom(el) { el.scrollTop = el.scrollHeight; }
scrollToBottom(document.getElementById('list'));
#list {
  height: 250px;
  overflow-y: scroll;
  border: 1px solid black;
}
#inner-list {
  display: flex;
  flex-direction: column-reverse;
}
.item {
  flex: 1;
  padding: 2em;
  border: 1px dashed green;
}
1
2
3
4
5
6
7
8
9

17
задан Mehrdad Afshari 24 June 2009 в 12:55
поделиться

6 ответов

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

18
ответ дан 30 November 2019 в 11:27
поделиться

MSDN:

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

, Но также и:

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

7
ответ дан 30 November 2019 в 11:27
поделиться

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

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

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

12
ответ дан 30 November 2019 в 11:27
поделиться

На 32-разрядной x86 платформе самая большая атомарная размерная часть памяти составляет 32 бита.

Это означает, что, если что-то пишет в или читает из 64-разрядной размерной переменной, для того чтения-записи возможно быть предвосхищенным во время выполнения.

  • , Например, Вы начинаете присваивать значение переменной на 64 бита.
  • После того, как первые 32 бита записаны, ОС решает, что другой процесс собирается получить процессорное время.
  • следующий процесс пытается считать переменную, которой Вы были посреди присвоения.

Это - всего одно возможное состояние состязания с 64-разрядным присвоением на платформе на 32 бита.

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

1
ответ дан 30 November 2019 в 11:27
поделиться

Если у Вас действительно есть совместно используемая переменная (скажите как статическое поле класса, или как поле общего объекта), и что поле или объект будут используемым перекрестным потоком, то, да, необходимо удостовериться, что доступ к той переменной защищен через атомарную операцию. x86 процессор имеет intrinsics, чтобы удостовериться, что это происходит, и это средство представлено через Систему. Поточная обработка. Взаимно блокируемые методы класса.

, Например:

class Program
{
    public static Int64 UnsafeSharedData;
    public static Int64 SafeSharedData;

    static void Main(string[] args)
    {
        Action<Int32> unsafeAdd = i => { UnsafeSharedData += i; };
        Action<Int32> unsafeSubtract = i => { UnsafeSharedData -= i; };
        Action<Int32> safeAdd = i => Interlocked.Add(ref SafeSharedData, i);
        Action<Int32> safeSubtract = i => Interlocked.Add(ref SafeSharedData, -i);

        WaitHandle[] waitHandles = new[] { new ManualResetEvent(false), 
                                           new ManualResetEvent(false),
                                           new ManualResetEvent(false),
                                           new ManualResetEvent(false)};

        Action<Action<Int32>, Object> compute = (a, e) =>
                                            {
                                                for (Int32 i = 1; i <= 1000000; i++)
                                                {
                                                    a(i);
                                                    Thread.Sleep(0);
                                                }

                                                ((ManualResetEvent) e).Set();
                                            };

        ThreadPool.QueueUserWorkItem(o => compute(unsafeAdd, o), waitHandles[0]);
        ThreadPool.QueueUserWorkItem(o => compute(unsafeSubtract, o), waitHandles[1]);
        ThreadPool.QueueUserWorkItem(o => compute(safeAdd, o), waitHandles[2]);
        ThreadPool.QueueUserWorkItem(o => compute(safeSubtract, o), waitHandles[3]);

        WaitHandle.WaitAll(waitHandles);
        Debug.WriteLine("Unsafe: " + UnsafeSharedData);
        Debug.WriteLine("Safe: " + SafeSharedData);
    }
}

результаты:

Небезопасный :-24050275641 Безопасный : 0

На интересной ноте стороны, я выполнил это в x64 режиме на Vista 64. Это показывает, что 64 битовых поля рассматривает как 32 битовых поля время выполнения, то есть, 64 битовых операции являются неатомарными. Кто-либо знает, является ли это проблемой CLR или проблемой x64?

2
ответ дан 30 November 2019 в 11:27
поделиться

Это действительно верно? Да, как оказалось. Если Ваши регистры только имеют 32 бита в них, и необходимо сохранить 64-разрядное значение к некоторой ячейке памяти, это собирается взять две операции загрузки и две операции хранилища. Если Ваш процесс прерван другим процессом между этой загрузкой/хранилищами двух, другой процесс мог бы повредить половину Ваших данных! Странный, но верный. Это было проблемой на каждом процессоре, когда-либо созданном - если Ваш тип данных будет длиннее, чем Ваши регистры, то у Вас будут проблемы параллелизма.

это что-то, о чем я волновался бы в реальном мире? Да и нет. Так как почти всему современному программированию дают его собственное адресное пространство, необходимо будет только волноваться об этом при выполнении многопоточного программирования.

, Если мое приложение является многопоточным, я должен действительно окружить все свои присвоения Int64 блокировкой кода? К сожалению, да, если Вы хотите стать техническими. Обычно легче на практике использовать Взаимное исключение или Семафор вокруг больших блоков кода, чем заблокировать каждый отдельный оператор набора на глобально доступных переменных.

0
ответ дан 30 November 2019 в 11:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: