Здравствуйте!
— Не хотите ли войти
2
ответа

Многопоточность

Здравствуйте!
Мой вопрос — про многопоточность, а именно:что нужно синхронизировать, а что нет.
Допустим, у нас есть объект с полем типа int, и нужно организовать доступ на чтение-запись этого поля из разных потоков. Вопросы следующие:

  1. Правда ли, что это поле не надо в явном виде синхронизировать для потоков, т.к. такие данные просто не возможно повредить? (Исхожу из того, что «атомами» потоков являются машинные команды, а там непосредственно присвоить что-либо переменной — это одна команда mov. Т.е. в любой момент времени в переменной лежит «целое» значение)
  2. Если на первый вопрос ответ утвердительный, то какие ещё типы не нуждаются в синхронизации? Видимо, все стандартные типы меньшей либо равной размерности чем int. Однако стоит вопрос о кастомных структурах, а так же о величинах типа long long int.
  3. Правда ли, что сгенерённое свойство для этого поля без модификатора nonatomic автоматом будет синхронизированным по объекту? (Имеется ввиду @synchronized(self)) Переформулируя вопрос: автогенерация свойств никак не зависит от типа поля, обслуживаемого свойством?
  4. Правда ли, что для любого стандартно-сгенерённого atomic-свойства одного класса выполняется правило, что в конкретный момент времени только оно одно из всех атомиков этого класса выполняется? А если я хочу убрать это свойство «мониторности», то мне надо заточить по замочку на каждую переменную и ручками прописать свойства?

Спасибо!

18 мая 2010
Чуть позже отвечу, там очень длинный ответ получается :)
alex
Супер. Спасибо!

Ответы

Итак, начнем. На пальцах, более подробные объяснения в других местах.

  • Во-первых, разберемся с атомарностью. Атомарность обозначает неделимость, неразрывность. То есть если у нас есть группа операций (обычно это инкремент + получение результата) — то она выполняется как единое целое. Если у нас есть два потока, которые делают эту операцию (реально — по две операции каждый), то они выполнятся строго последовательно, а не «инкремент раз — инкремент два — получение раз — получение два».
  • Во-вторых, что такое синхронизация. Это когда у нас есть объект (семафор кажется), и мы говорим: «если семафор открыт — закрыть, иначе стоять тут, пока не откроют». Это обычно реализуется при помощи тех самых атомарных операций и позволяет (при удачном стечении обстоятельств) делать «атомарными» сравнительно большие блоки кода.
  • «Атомарные команды» — действительно машинные. Их много разных и этот список сильно зависит от архитектуры процессора, на котором мы все это исполняем. То есть ответ на первые два вопроса: «зависит от архитектуры». Long long тоже может иметь атомарные операции. Какие являются атомарными в iPhone — не знаю.
  • про nonatomic можно прочитать в документации. Если его не писать, генерится такой код (если же там nonatomic, то значение возвращается без лока. Как именно этот лок реализован — не сказано):
[_internal lock]; // lock using an object-level lock
id result = [[value retain] autorelease];
[_internal unlock];
return result;
  • по 4му вопросу. Этого никто не гарантирует. Atomic всего-лишь гарантирует, что в многопоточной среде ничего не сломается. То есть если А читает пропертю, а Б и В — в это же время ее записывают, то А может получить любое из трех значений.

Как-то так. Вот тут есть еще немного информации про это: stackoverflow.com/questions/588866/objective-c-properties-atomic-vs-nonatomic

18 мая 2010
ссылку конечно же давно читал, однако на конкретные вопросы она ответов, кажется, не даёт (ну или я просто не нашёл?)
  1. Да, тут всё понятно
  2. Вообще говоря, то, что Вы описали, называется spinlock-ом. Семафоры имеют некоторую «ёмкость» — количество потоков, которое можно запихнуть в охраняемую секцию. При ёмкости равной единице семафор ведёт себя так же, как и спинлок
  3. В первом вопросе я говорил именно про поле типа int, т.к. я откуда-то слышал, что длинна int-а равна длинне указателя, который в свою очередь является одним словом. (не получилось сходу найти этого в спецификации ANSI, нашёл только вот тут:tigcc.ticalc.org/doc/keywords.html#int) То есть на 16-битных платформах int будет 16битный, а на 32-битных — 32-битным. Таким образом этот тип «нативен» для платформы. Ну и наконец просто довод с точки зрения здравого смысла: как может попортиться int? Когда запишутс его первые два байта, второй поток успеет считать его? или что? Звучит сильно сомнительно. :)
  4. Комментарий «lock using an object-level lock» наводит на мысль, что там стоит синхронизация по объекту. Правда, одно я теперь знаю точно(провёл небольшой эксперимент): это скорее всего внутренний лок, и поэтому @synchronize по этому же объекту отлично выполняется вместе с доступом в свойства. Ну а больше, на самом деле, ничего не надо. Спасибо!
25 мая 2010
Про спинлоки ничего не скажу, про емкость семафоров — тоже. Там все сложно и плохо.
alex
Про атомарность на таком уровне — ничего сказать не могу. Все-таки я обычно более высокоуровневые программы пишу. Да, про связь указателя и int говорилось, но что из этого следует — черт его знает.
alex
@synchronize в том же потоке? Или в другом? В том же — и должно выполняться. В другом — там интереснее, если выполняется, то тогда что же ж это за лок?
alex
@synchronize в другом потоке. Впрочем, вот код: http://paste.org/pastebin/view/18937 Скорее всего это просто приватное поле в классе NSObject, выглядит как-нибудь так: NSLock *_internal; Таким образом
:( Я говорил, что мониторность при такой реализации есть, однако она длится очень малый промежуток времени, т.к. автогенерённые свойства просты и мгновенно возвращают управление
Зарегистрируйтесь или войдите, чтобы добавить свой комментарий или ответ на вопрос.
© 2009-2012, ООО «Инру»
Вход
Имя пользователя:
Пароль:
Или…
Twi
Отмена
Войти
Восстановить забытый пароль…