Многопоточность и разделяемые ресурсы.

YUBA
Дата: 05.04.2014 17:22:51
Имеется приложение в котором работают 3 потока - приложения и 2 дополнительных. Потоки читают одни и теже данные, включая данные, полученные другими потоками, но пишут в разные места, и, вроде, никакой конкуренции не было. Однако понадобилось, чтобы потоки обращались к одному и тому-же функционалу. Для определенности пусть это будет функция
double f(double x, double y, int z)
{
double a,b;
a=x; b=y;
Thread.Sleep(z); //типа что-то делаем
return a+b;
}

Что будет если потоки обратятся к функции практически одновременно? Таким, например, образом 1-й - f(2,2,20), 2-й - f(3,3,10).

1. Все будет ОК, ведь обращаемся мы к Debug.WriteLine(""), и никаких конфликтов.
2. NET блокирует функцию до освобождения ресурсов и другому потоку придется подождать, и все опять ОК.
3. И тот и другой потоки получат и в итоге одинаковый ответ, например 6.

В книжках днозначного ответа что-то не нашел - 50/50.


"Есть многое на свете, друг Горацио, что и не сразу в голову придет."
М. Твен "Приключения Геккельбери Финна"
Pallaris
Дата: 05.04.2014 18:34:17
YUBA
Что будет если потоки обратятся к функции практически одновременно? Таким, например, образом 1-й - f(2,2,20), 2-й - f(3,3,10).


1ый уснет на 20мс и вернет 4, второй на 10 мс и вернет 6. С чего бы быть по-другому?
Arm79
Дата: 05.04.2014 18:37:17
YUBA,

В вашем случае, если работа будет идти только с параметрами, переданными в функцию, то никаких проблем не будет. Функция - это выделенный кусок исполнимого кода, и его синхронизировать с чем то не нужно абсолютно. Синхронизируют, при необходимости, только доступ к данным. Например, передающиеся по ссылке объекты.
YUBA
Дата: 05.04.2014 22:24:14
Arm79 , Если прав Pallaris , и на время выполнения функции, она блокируется Фреймвоком, то никаких проблем не должно быть.
Однако, в одной из книг, в качестве примера, разбирался доступ к функции именно в таком ключе, что и в моем вопросе.
[quote Arm79 ]Функция - это выделенный кусок исполнимого кода,[/quote] и ее экземпляр не создается при исполнении. Если поток заходит в функцию и присваивает a=2, b=2, после чего второй поток заходит в нее-же и присваивает тем-же ячейкам памяти a=3, b=3, то первая функция на выходе return a+b получит 6, а не 2+2=4.
Arm79
Синхронизируют, при необходимости, только доступ к данным. Например, передающиеся по ссылке объекты.

Доступ к функции, как правило, и есть доступ к объектам и получение ссылки на объект. И что там происходит в объекте, далеко не всегда очевидно.
Хорошо пусть будут данные, пусть при обращении к функции объекта мы должны получить коллекцию строк (Rows), а другой поток одновременно хочет получить некую другую коллекцию.
Хотелось бы подчеркнуть, что потоки пишут данные в разные места, и здесь четко разделены, а вот читают одни и те-же, либо данные других потоков, но чтение идет в разном контексте. Т.е. обращаясь к одним и тем-же функциям объектов делают разные вызовы.
Хотелось бы, чтобы Pallaris был прав, но где это четко прочитать?
Если возможно, цитату с ссылкой. К сожалению, в Инете ищется все хуже и хуже. :(
Arm79
Дата: 05.04.2014 23:49:25
YUBA
чего второй поток заходит в нее-же и присваивает тем-же ячейкам памяти a=3, b=3

Осталось только понять, с чего вы взяли, что там те же ячейки? В вашем примере параметры метода - примитивные типы, следовательно, происходит передача по значению (а не по ссылке). Из чего следует, что каждый вызов метода приведет к копированию входных данных. То есть ячейки будут разными по любому.

YUBA
Хотелось бы, чтобы Pallaris был прав

Может, вы огорчитесь, но Pallaris прав.

YUBA
Хотелось бы подчеркнуть, что потоки пишут данные в разные места, и здесь четко разделены, а вот читают одни и те-же, либо данные других потоков, но чтение идет в разном контексте. Т.е. обращаясь к одним и тем-же функциям объектов делают разные вызовы.

Тут вообще ничего не понятно


YUBA
пусть при обращении к функции объекта мы должны получить коллекцию строк (Rows), а другой поток одновременно хочет получить некую другую коллекцию.

А в чем вопрос то? Если функция создает в своем теле коллекцию строк (а не копирует откуда то), то эта коллекция никак не перемешается с другой
Где-то в степи
Дата: 06.04.2014 00:10:45
YUBA,
YUBA
К сожалению, в Инете ищется все хуже и хуже. :(
гыгыгы
Узбагойтесь, вернитесь к истокам : организация памяти, коль затронули функции - почитайте про стек вызовов (call stack)
с такой кашей в голове дальше двигать нельзя ((
YUBA
Дата: 06.04.2014 00:45:34
Arm79,
Читаем Рихтера "... Net via C#"
Рихтер
В то же время FCL не гарантирует безопасности в отношении потоков
экземплярным методам, так как введение в них запирающего кода слишком
сильно сказывается на производительности. Более того, если каждый экземплярный
метод начнет выполнять запирание и отпирание, все закончится тем,
что в приложении в каждый момент времени будет исполняться только один
поток, что еще больше снизит производительность. Как уже упоминалось, поток,
конструирующий объект, является единственным, кто имеет к нему доступ.
Другим потокам данный объект недоступен, а значит, при вызове экземплярных
методов синхронизация не требуется. с. 855

Эт хорошо, что прав. И скорее всего прав. Но понимания физики процесса нет.
Но получается, что при обращении к функции объекта из потока, должна создаваться полная копия объекта содержащего эту функцию и взаимосвязанных объектов. Ведь она, функция, может содержать множество других функций как самого объекта, так и других объектов, а те в свою очередь... до бесконечности. Такое предположение - это дурдом. Вряд-ли это возможно.
Если это не так, никакое копирование переменных в вызове функции не поможет, да и копируются они в функцию (точки входа). Что мешает их значения изменить другому потоку? Т.е., для нашего примера a и b должны поменяться на с 2, 2 на 3,3 при обращении из другого потока.
Копирование же значений переменных в вызываемую функцию безопасно только для вызывающего объекта, для чего, собственно и сделано. Но никакой гарантии, что копии кто-то не изменит и функция будет работать нештатно.
Но Вы сами писали
Arm79
Функция - это выделенный кусок исполнимого кода
Т.е.. видимо, для всех потоков, это одни и те же ячейки памяти.
YUBA
Дата: 06.04.2014 01:26:24
Где-то в степи, я собственно и хочу разобраться.
А про стек - каждый поток имеет свой стек.
YUBA
Дата: 06.04.2014 01:34:15
Рихтер
Когда
поток конструирует новый объект при помощи оператора new, оператор возвращает
ссылку на этот объект. Причем в этот момент ссылка имеется только у создающего
объект потока, другие потоки не имеют к нему доступа. Если не передавать
эту ссылку другому потоку, который может использовать объект одновременно
с потоком, создавшим объект, необходимость в синхронизации отпадает.

В моем случае все потоки работают с одними и теми же объектами и их методами.
Pallaris
Дата: 06.04.2014 09:41:38
YUBA,

в твоем случае - это в каком? В том примере, что ты привел, нет никаких объектов, и при вызове метода все переменные a,b,x,y,z для любого из потоков - уникальные (находятся в разных ячейках памяти в момент выполнения)