2008-09-16 4 views
2

Я понимаю условия гонки и как с несколькими потоками, обращающимися к одной и той же переменной, обновления, сделанные одним, могут игнорироваться и перезаписываться другими, но что, если каждый поток записывает одно и то же значение (не разные значения) в одну и ту же переменную; может ли это вызвать проблемы? Может ли этот код:Можно ли иметь несколько потоков, которые записывают одни и те же значения в одни и те же переменные?

GlobalVar.property = 11;

(при условии, что для свойства никогда не будет назначено ничего, кроме 11), вызывают проблемы, если несколько потоков выполняют его одновременно?

+0

Какой язык вы используете? – GateKiller 2008-09-16 13:25:55

ответ

1

Я ожидаю, что результат будет неопределенным. Как в этом будет отличаться от компилятора к complier, langauge к языку и OS к ОС и т. Д. Так что нет, это небезопасно

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

2

Это зависит от работы, фактически выполняемой этим утверждением. Все еще могут быть случаи, когда происходит что-то плохое - например, если класс C++ перегрузил оператор = и делает что-то нетривиальное в этом утверждении.

У меня есть случайно написанный код, который сделал что-то вроде этого с типами POD (встроенные примитивные типы), и он работал нормально - однако это определенно не очень хорошая практика, и я не уверен, что он надежный.

Почему бы не просто заблокировать память вокруг этой переменной, когда вы ее используете? Фактически, если вы как-то «знаете», это единственный оператор записи, который может произойти в какой-то момент вашего кода, почему бы просто не использовать значение 11 напрямую, а не записывать его в общую переменную? (редактировать: Я думаю, что лучше использовать имя константы вместо magic number 11 непосредственно в коде, кстати.)

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

1

В целом, это не считается безопасным, если ваша система не обеспечивает атомную работу (операции, которые гарантированно выполняются за один цикл). Причина в том, что, хотя оператор «С» выглядит просто, часто происходит ряд основных операций сборки.

В зависимости от вашей операционной системы, Есть несколько вещей, которые вы могли бы сделать:

  • Возьмите взаимное исключение семафор (мьютекса) для защиты доступа
  • в некоторых ОС, вы можете временно отключить упреждение, что гарантирует ваш поток не будет заменен.
  • Некоторые ОС предоставляют семафор писателя или читателя, который более эффективен, чем простой старый мьютекс.
-1

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

+0

№ Atomity гарантирует, что другие потоки никогда не будут видеть _half_ ваше значение. Видимость новой ценности - это другое дело. – 2008-10-11 15:27:07

7

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

Проблема заключается в том, что, предположительно, вы пишете этот бит общего состояния по какой-либо причине - чтобы сигнализировать о том, что что-то произошло? Здесь он падает: когда у вас нет конструкций блокировки, нет никакого подразумеваемого порядка доступа к памяти вообще. Трудно указать на то, что здесь не так, потому что ваш пример фактически не содержит использования переменных, так вот trivialish примера в нейтральном C-подобный синтаксис:

int x = 0, y = 0; 

//thread A does: 
x = 1; 
y = 2; 
if (y == 2) 
    print(x); 

//thread B does, at the same time: 
if (y == 2) 
    print(x); 

Thread А всегда будет печатать 1, но полностью верно для потока B для печати 0. Порядок операций в потоке A требуется только для наблюдения из кода, выполняемого в потоке A. В потоке B разрешено видеть любую комбинацию состояния. Запись в x и y может не произойти по порядку.

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

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

0

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

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

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

Компиляторы, JIT, CPU caches. Они все пытаются сделать ваш код запущенным как можно быстрее, и если вы не будете делать каких-либо явных требований к видимости памяти, то они воспользуются этим. Если не на вашей машине, то кто-то elses.

1

Вот мой вопрос.

У вас есть два или более потока, которые записываются в переменную ... как флаг состояния или что-то в этом роде, где вы только хотите знать, было ли одно или несколько из них истинными. Затем в другой части кода (после того, как нити в комплекте) вы хотите проверить и посмотреть, если по крайней мере, на резьбе установить этот статус ... например

bool flag = false 
threadContainer tc 
threadInputs inputs 

check(input) 
{ 
    ...do stuff to input 
    if(success) 
     flag = true 
} 

start multiple threads 
foreach(i in inputs) 
    t = startthread(check, i) 
    tc.add(t) // Keep track of all the threads started 

foreach(t in tc) 
    t.join() // Wait until each thread is done 

if(flag) 
    print "One of the threads were successful" 
else 
    print "None of the threads were successful" 

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

+0

Под моделью памяти Java5, о которой я знаю больше всего, этот код должен быть в порядке, потому что запуск и объединение потоков - это законные способы совершения межсетевых соединений и будут иметь подходящие mfence() es. – 2008-10-11 15:31:00

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