LINUX.ORG.RU

Замыкания (closure) и многопоточность


0

1

Как я понял, замыкания связывают некие переменные с заданной функцией, и при повторном вызове функция помнит контекст вызова предыдущего. А как такое поведение сочетается с многопоточностью? Если один поток создал функции контекст, то что будет, если после функцию дёрнет другой поток? Контекст пересоздастся для нового потока, или имеем полную аналогию с глобальными переменными, и требуется всяческая синхронизация?

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

Legioner ★★★★★
()
Ответ на: комментарий от one_more_hokum

> А есть языки, позволяющие множить контекст между потоками?

Есть языки в которых можно вызывать замыкание из разных потоков, и не беспокоиться о синхронизации. Например Clojure.

Если свободные переменные нельзя менять, то нет необходимости в синхронизации или создании копий для разных потоков.

nozh
()
Ответ на: комментарий от one_more_hokum

Не совсем понятно, что именно нужно, но в коммон лиспе есть динамическое связывание (против обычного лексического). Там контекст множится по потокам, если еще не забыл.

dave ★★★★★
()
Ответ на: комментарий от one_more_hokum

Представь, что вызываешь метод одного и того же объекта из двух разных тредов. Вот при вызове замыкания происходит все в точности то же самое.

anonymous
()
Ответ на: комментарий от one_more_hokum

Тогда можно обратиться к таким языкам как F# или Scala. Когда создается функция (замыкание), то фактически с точки зрения ООП создается новый объект автоматически сгенерированного класса. У этого объекта есть обычно один главный метод. Он называется или Invoke, или Apply. Это и есть вызов функции. У этого объекта есть еще поля. В эти поля и кладутся значения, захваченные замыканием. Эти значения хранятся в этом объекте.

Поэтому если функция одна, а потоков много, то все потоки будут обращаться к одним и тем же значениям полей сгенерированного объекта. Так это выглядит с точки зрения ООП. И это был lexical scope. Такие переменные видны только локально.

Еще есть dynamically scoped переменные в коммон лиспе. Вот, они фактически глобальны, но разделены по потокам.

Но это еще не конец... Почти все переменные могут быть разделены по доменам приложения, но это уже .NET :)

dave ★★★★★
()

> Как я понял, […], и при повторном вызове функция помнит контекст вызова предыдущего

Ты не правильно понял. Читай про lexical scoping и dinamic scoping. Ничто из них не соответствует твоему «помнит контекст предыдущего вызова».

anonymous
()
Ответ на: комментарий от one_more_hokum

Кстати, некоторые языки допускают некоторые вольности при захвате замыкания. Переменные могут неявно захватываться по ссылке. В F# это не так. Там можно захватить только значение или явно саму ссылку. Очень помогает пониманию и позволяет не допускать глупых ошибок.

dave ★★★★★
()
Ответ на: комментарий от one_more_hokum

А проблемы с многопоточностью возникают только тогда, когда отходишь от функционального стиля и начинаешь прибегать к побочным эффектам. Иммутабельные же значения (в языках с GC) потокобезопасны.

dave ★★★★★
()
Ответ на: комментарий от dave

>> Не совсем понятно, что именно нужно, но в коммон лиспе есть динамическое связывание (против обычного лексического). Там контекст множится по потокам, если еще не забыл.

Динамическое связывание _как_правило_ происходит в каждом потоке отдельно. Но это не описано в стандарте и конкретная реализация не обязана так делать.

Лексическое связывание также может быть, а может и не быть потокобезопасным, все зависит от реализации. В стандарте этого опять же нет.

cathode
()
Ответ на: комментарий от cathode

> Лексическое связывание также может быть, а может и не быть потокобезопасным, все зависит от реализации. В стандарте этого опять же нет.

И как работает потокобезопасное лексическое связывание для замыканий (функций)? Ты себе это представляешь?

dave ★★★★★
()
Ответ на: комментарий от dave

>> И как работает потокобезопасное лексическое связывание для замыканий (функций)? Ты себе это представляешь?

Также как потокобезопасное динамическое - копированием связанных переменных (точнее фрейма).

cathode
()
Ответ на: комментарий от cathode

И как это работает, если замыкание создает один поток, а другие только вызывают функцию? Откуда берутся значения в других потоках?

dave ★★★★★
()
Ответ на: комментарий от dave

>то фактически с точки зрения ООП создается новый объект автоматически сгенерированного класса

В C++ также.

Yareg ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.