2009-02-04 1 views
8

Переменные 'boolean' являются потокобезопасными для чтения и записи из любого потока? Я видел некоторые ссылки в новостных группах, чтобы сказать, что они есть. Доступны ли какие-либо другие типы данных? (Перечислимые типы, короткие int, возможно?)Список типов данных Delphi с «потокобезопасными» операциями чтения/записи?

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

ответ

7

Обратите внимание, что вы можете сделать практически все в delphi unthreadsafe. В то время как другие упоминают проблемы выравнивания по логическому, это в какой-то мере скрывает реальную проблему.

Да, вы можете читать логическое значение в любом потоке и писать в boolean в любом потоке, если он правильно выровнен. Но чтение из логического значения, которое вы меняете, не обязательно «потокобезопасно». Скажем, у вас есть логическое значение, которое вы установили в true, когда вы обновили номер, чтобы другой поток читал число.

if NumberUpdated then 
begin 
    LocalNumber = TheNumber; 
end; 

Благодаря оптимизации процессор делает Thenumber может быть прочитан перед NumberUpdated читается, таким образом, вы можете получить старое значение Thenumber Eventhough вы обновленное NumberUpdated последним.

Ака, ваш код может стать:

temp = TheNumber; 
if NumberUpdated the 
begin 
    LocalNumber = temp; 
end; 

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

Bonus реклама:

В библиотеке VCL не поточно. Сохраните всю модификацию файлов ui в основной теме. Также создайте все элементы ui в основной теме.

Многие функции также не являются потокобезопасными, в то время как другие, это часто зависит от основных вызовов winapi.

Я не думаю, что «список» был бы полезен, поскольку «потокобезопасность» может означать много чего.

+0

+1, очень хорошие очки. Для кого-то заинтересованного, посетите, например, http://en.wikipedia.org/wiki/Memory_barrier и связанную информацию. – mghie

5

В 32-разрядной архитектуре только правильно выровненные 32-разрядные или менее типы данных должны считаться атомарными. 32-битные значения должны быть 4-выровнены (адрес данных должен быть равномерно делимым на четыре). Вероятно, вы не столкнетесь с чередованием на таком ограниченном уровне, но теоретически у вас может быть двойная, Int64 или Extended неатомная запись.

+0

В течение очень долгого времени выровненное 64-битное чтение/запись было атомарным на оборудовании x86, даже в 32-разрядном режиме. –

+0

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

7

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

Существует ряд функций, которые позволяют выполнять атомарные операции: сблокированные приращения, блокированные декременты и блокированный обмен. Это общая концепция, не имеющая ничего общего с Windows, x86 или Delphi. Для Delphi вы можете использовать функции InterlockedFoo() для Windows API, вокруг них есть несколько оберток. Или напишите свое. Функции работают с целыми числами, поэтому вы можете иметь атомное приращение, уменьшение и обмен целыми числами (32 бит) с ними.

Вы также можете использовать ассемблерные и префиксные операторы с префиксом блокировки.

Для получения дополнительной информации см. Также this StackOverflow вопрос.

0

Инди код содержит некоторые безопасные типы данных атомных/потоков в IdThreadSafe.pas:

  • TIdThreadSafeInteger
  • TIdThreadSafeBoolean
  • TIdThreadSafeString
  • TIdThreadSafeStringList и еще немного ...
1

С многоядерной обработкой RISC и отдельным ядром c в то время как память находится в смеси современного процессора, не более того, любая «тривиальная» высокоуровневая конструкция для чтения или записи на высоком уровне (или, во всяком случае, многократные 8086 «атомные» инструкции по сборке) можно считать атомным. Действительно, если инструкция ассемблера специально не спроектирована как атомарная, она, вероятно, не является атомарной - и это включает в себя большинство механизмов чтения в памяти. Даже длинное целое число, читаемое на уровне ассемблера, может быть повреждено одновременной записью из другого процессорного ядра, которое использует одну и ту же память и использует операции обновления асинхронного кэша на уровне RISC-процессора. Помните, что на процессоре, состоящем из нескольких ядер RISC, даже инструкции на языке ассемблера - это просто инструкции кода более высокого уровня! Вы никогда не знаете, как они реализуются на уровне бит, и может быть не совсем то, что вы ожидали, если бы вы читали старое руководство по ассемблеру 8086 (одноядерное). Windows предоставляет ядерные операторы, совместимые с национальной системой, и вам будет рекомендовано использовать их, а не делать какие-либо базовые предположения об атомных операциях.

Зачем использовать операторы Windows? Потому что одна из первых вещей, которые делает Windows, - это установить, на что машина работает. Одним из ключевых аспектов, которые он обеспечивает, становится всецело, какие атомарные операции существуют и как они будут работать. Если вы хотите, чтобы ваш код работал в будущем на любом будущем процессоре, вы можете либо дублировать (и постоянно обновлять) все эти усилия в своем собственном коде, либо вы можете использовать тот факт, что Windows все это уже при запуске. Затем он включил необходимый код в свой API во время выполнения.

Прочитайте страницы MSDN по атомным операциям. Интерфейс Windows API подходит для вас. Иногда они кажутся неуклюжими или неуклюжими, но они являются будущим доказательством, и они всегда будут работать точно так же, как это говорит на жестяне.

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

Всякий раз, когда вы пишете код, всегда полезно понять Parsimony и рассмотреть Occam's razor. Другими словами, если Windows уже делает это, и вашему коду требуется Windows для запуска, то используйте то, что Windows уже делает, вместо того, чтобы опробовать множество альтернативных и все более сложных гипотетических решений, которые могут работать или не работать. Выполнение чего-либо еще - это просто трата вашего времени (если, конечно, это то, что вы делаете).

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