В качестве обходного пути вы можете распространять стили своего контейнера между двумя различными контейнерами:
Если вы хотите, чтобы по умолчанию она была прокручена вниз, вы можете использовать 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
Это не о каждой переменной, с которой Вы встречаетесь. Если некоторая переменная используется в качестве общего состояния или чего-то (включая, но не ограничивается приблизительно static
поля), необходимо заботиться об этой проблеме. Это - полностью надуманный вопрос для локальных переменных, которые не подняты в результате того, чтобы быть закрытым в закрытии или преобразовании итератора и используются единственной функцией (и таким образом, единственный поток) за один раз.
MSDN:
Присвоение экземпляра этого типа не ориентировано на многопотоковое исполнение на всех аппаратных платформах, потому что двоичное представление того экземпляра могло бы быть слишком большим для присвоения в единственной атомарной операции.
, Но также и:
Как с любым другим типом, читая и пишущий в совместно используемую переменную, которая содержит экземпляр этого типа, должен быть защищен блокировкой для гарантии потокобезопасности.
Даже если бы записи были атомарные, возможности - Вы, должен был бы все еще вынуть блокировку каждый раз, когда Вы получили доступ к переменной. Если бы Вы не сделали этого, то необходимо было бы, по крайней мере, сделать переменную volatile
, чтобы удостовериться, что все потоки видели новое значение в следующий раз, когда они читают переменную (который является почти всегда, что Вы хотите). Это позволяет Вам сделать атомарные, энергозависимые наборы - но как только Вы хотите сделать что-либо более интересное, такое как добавление 5 к нему, Вы вернулись бы к блокировке.
Блокировка бесплатное программирование должно очень, очень трудно для разбираний. Необходимо знать точно , что Вы делаете и сохраняете сложность к максимально маленькой части кода. Лично, я редко даже пытаюсь делать попытку его кроме для очень хорошо известных шаблонов, таких как использование статического инициализатора для инициализации набора и затем чтения из набора без блокировки.
Используя Interlocked
класс может помочь в некоторых ситуациях, но почти всегда намного легче просто вынуть блокировку. Неоспоримые блокировки являются "довольно дешевыми" (по общему признанию, они становятся дорогими с большим количеством ядер, но также - все) - не бездельничают с кодом без блокировок, пока у Вас нет достоверных свидетельств, что он на самом деле будет иметь значительное значение.
На 32-разрядной x86 платформе самая большая атомарная размерная часть памяти составляет 32 бита.
Это означает, что, если что-то пишет в или читает из 64-разрядной размерной переменной, для того чтения-записи возможно быть предвосхищенным во время выполнения.
Это - всего одно возможное состояние состязания с 64-разрядным присвоением на платформе на 32 бита.
Однако даже с переменной на 32 бита могут быть условия состязания с чтением и записью для этого, что любая совместно используемая переменная должна синхронизироваться в некотором роде для решения этих условий состязания.
Если у Вас действительно есть совместно используемая переменная (скажите как статическое поле класса, или как поле общего объекта), и что поле или объект будут используемым перекрестным потоком, то, да, необходимо удостовериться, что доступ к той переменной защищен через атомарную операцию. 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?
Это действительно верно? Да, как оказалось. Если Ваши регистры только имеют 32 бита в них, и необходимо сохранить 64-разрядное значение к некоторой ячейке памяти, это собирается взять две операции загрузки и две операции хранилища. Если Ваш процесс прерван другим процессом между этой загрузкой/хранилищами двух, другой процесс мог бы повредить половину Ваших данных! Странный, но верный. Это было проблемой на каждом процессоре, когда-либо созданном - если Ваш тип данных будет длиннее, чем Ваши регистры, то у Вас будут проблемы параллелизма.
это что-то, о чем я волновался бы в реальном мире? Да и нет. Так как почти всему современному программированию дают его собственное адресное пространство, необходимо будет только волноваться об этом при выполнении многопоточного программирования.
, Если мое приложение является многопоточным, я должен действительно окружить все свои присвоения Int64 блокировкой кода? К сожалению, да, если Вы хотите стать техническими. Обычно легче на практике использовать Взаимное исключение или Семафор вокруг больших блоков кода, чем заблокировать каждый отдельный оператор набора на глобально доступных переменных.