![]() |
Модераторы: feodorv, GremlinProg, xvr, Fixin |
![]() ![]() ![]() |
|
Paspartu |
|
||||||
Шустрый ![]() Профиль Группа: Участник Сообщений: 67 Регистрация: 3.5.2007 Репутация: нет Всего: нет |
Доброго времени суток!
…Вот, разбираюсь с потоками, прочитал Дж. Рихтера, но возникли вопросы по синхронизации и вообще в каких случаях ее делать, так что вопрос чисто теоретический: Допустим есть функция : (.cpp):
И где-то класс CBaseThread который создает поток со static методом:
// Где-то в производном классе:
|
||||||
|
|||||||
xvr |
|
||||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 40 Всего: 223 |
Если что то модифицирует - то надо смотреть, что и как (в общем случае нужно синхронизировать) Опять же - если необходимо что бы разные потоки видели общие данные, модифицируемые этой функцией - то нужна синхронизация. Если же вызовы из разных потоков не влияют друг на друга - то можно сделать несколько экземпляров (но не функции, а данных, с которыми она работает)
|
||||||
|
|||||||
Earnest |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Экс. модератор Сообщений: 5962 Регистрация: 17.6.2005 Где: Рязань Репутация: 33 Всего: 183 |
Не совсем так. Если IsPrime читает переменные, которые могут изменять другие функции (конкурентно), то тоже нужно защищать. Даже простые переменные типа int. И вообще, пока не встали вопросы производительности, я бы в начале всех функций, которые могут вызываться из разных потоков, поставила блокировку. -------------------- ... |
|||
|
||||
jonie |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 5613 Регистрация: 21.8.2005 Где: Владимир Репутация: 7 Всего: 118 |
Earnest, чтение потокобезопасно. Лично я не вижу смысла ставить блокировку на чтение - на запись ставить надо. Паттерн UnitOfWork в общем с блокировкой типа "заблокировал и всё че надо поменял одним махом".
В .NET например нет функций чтения Interlocked* - именно потому что всегда прочтенное значение будет именно то которое надо, как бы логически это не смотрелось неверным - просто один поток успеть может прочесть до изменения - но бловировка тут ничего не даст - он все-равно прочтет "старое" значение. -------------------- Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет... |
|||
|
||||
GremlinProg |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
а Interlocked* и введены как раз для изменения значения, читать - понятно можно и без синхронизации,
но вот если к примеру идет очень точный счет среди потоков, и они для этого счета используют общую переменную, которая постоянно меняется этими же потоками, то простое чтение без синхронизации может привести к неожиданным результатам: переменная еще не дописана потоком 1, а поток 2 уже начал ее читать, причем, когда поток 2 закончил ее читать, полток 1 только закончил в нее писать что получится? поток 2 может не получить не только нового значения переменной, но и не старого, т.е. поток 2 в момент расчета следующей итерации точно не опирается на расчеты потока 1 в таких случаях синхронизация нужна даже на чтение, да это не только атомарной переменной касается, вот например идет заполнение массива потоком 1, поток 2 может его спокойно читать без синхронизации, но что он в итоге прочитает, если для потока 2 массив актуален только в заполненном состоянии? -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 40 Всего: 223 |
Но может быть не атомарно, в таком случае не гарантируется целостность считанного значения |
|||
|
||||
jonie |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 5613 Регистрация: 21.8.2005 Где: Владимир Репутация: 7 Всего: 118 |
GremlinProg, xvr, читать можно без локов, всегда. Никакая атомарность чтения не проблема, т.к. запись атомарна (вот где локи нужны) - остальные ждут пока все запишется.
Чета я в общем сомневаюсь что вышеописанная неатомарность чтения на intel совместимых процах реализуема при должном обеспечении блокировки при записи Добавлено @ 11:00
В общем не надо путать проблемы дизайна решения и проблемы потоков. Это сообщение отредактировал(а) jonie - 23.6.2010, 11:03 -------------------- Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет... |
||||
|
|||||
GremlinProg |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
это все правильно до тех пор, пока процессор и/или ядро в единственном экземпляре, т.е. в полном отсутствии параллелизма Добавлено через 1 минуту и 11 секунд в наше время это уже редкость -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
Paspartu |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 67 Регистрация: 3.5.2007 Репутация: нет Всего: нет |
Доброго времени суток!
Всем огромное спасибо за разъяснение, но поправьте меня если я ошибаюсь: 1. Синхронизацию нужно проводить только при доступе различных потоков к общим данным Таким образом: a). Если 1-й поток читает к примеру массив то если в этот момент 2-й поток пытается его изменить то его нужно блокировать, пока чтение не будет завершено. б). Если 1-й пишет, а 2-й читает то нужна блокировка 2-го потока так что бы он читал уже измененные значения. Без нее ничего страшного не произойдет? Кроме того, что будет прочитано старое значение? в). Если оба потока читают – блокировка какого-либо из них не нужна. 2. Если происходит вызов (одной и той же) функции которая возвращает значение сколько угодными потоками то синхронизация не нужна так как общих данных в ней нет, а возвращаемое значение, ее параметры и ее локальные переменные будут для каждого потока своими? 3. Запутался с классами и их методами… если класс создан через new и в каждом потоке используется указатель на него, что будет копироваться в стек потока? К примеру, в разных потоках через указатель будет вызываться один и тот же метод, аналогично будут копироваться только возвращаемое значение, параметры метода и его локальные переменные? Или повторюсь, есть ли необходимость для каждого потока создавать свой экземпляр класса? т.е. есть класс:
Если при вызове методов F1, F2 их параметры будут копироваться в стек потока, то что будет с его членами m_n, m_db, m_ch? Если мы используем оди и тот же указатель на этот класс в разных потоках. В каких случаях нужна синхронизация методов F1, F2? Только если они изменяют значения членов класса? Нужно ли синхронизировать const или нет, т.к. он не изменяет объект? Опять же таки если в классе нет общих данных нужных нескольким потокам, к примеру в нем несколько методов, а члены int m_n и т.д. испоьзуются как промеж. Значения вычислений(образно)… можно ли при исопользовании одного экземляра для разных потоков обойтись без синхронизации, или она небходима, т.к. члены int m_n и т.д. все таки будут общими и они не будут копироваться в стек? Короче говоря… как бы с функциями вроде понятно, что они (значения локальных переменых и т.д.) копируются в стек, а если используется общий указатель на класс? Копирование в стек потока параметров и локальных переменных метода происходит в момент вызова потоком данного метода? А что происходит с членами класса (не методами) они становяться общими? А если мы в каждом потоке используем свой экземпляр то, синхронизация не нужна т.к. общих данных нет? … Много налил воды… но все же помогите разобраться раз и навсегда… наверное. ![]() |
|||
|
||||
GremlinProg |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2706 Регистрация: 9.8.2005 Где: Тюмень Репутация: 99 Всего: 106 |
не-не, в одном потоке такого эффекта не получишь -------------------- "Гений всегда разумнее, чем умнее. Ум — это машина, разум — водитель этой машины." |
|||
|
||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 40 Всего: 223 |
Проблема, даже с атомарной записью. Пример - читаем 64х битное значение на 32х битном процессоре. Чтение будет производится в 2 приема (2 по 32 бита). Другой процесс в это время инвертирует значение переменной. Предположим, что в начале переменная равна 0, чтение начинается с младшего слова, и 2й процесс записал новое значение между 2мя чтениями 1го процесса. В результате 1й процесс прочтет 0xFFFFFFFF00000000, что неверно с любой точки зрения ![]() |
|||
|
||||
xvr |
|
||||||||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 40 Всего: 223 |
Если ЛЮБОЙ поток модифицирует содержимое массива, то нужен какой либо способ СИНХРОНИЗАЦИИ доступа к массиву. Эта синхронизация должна в том или ином виде быть применена ко ВСЕМ потокам, которые работают с массивом, т.е. это по сути принадлежность массива, а не потока. В случае если только 1 поток пишет данные, а все остальные читают, синхронизация может быть сильно упрощена (вплоть до полного отсуствия, если изменяемые данные имеют длинну 32 бита и выровненны на 4х байтовую границу) Может сильно помочь набор Interlocked* функций (уже упоминались). С ними можно избежать блокировки потоков Да Да. Но вот члены класса (переменные) будут общими
Члены классов (переменные) ничем не отличаются (для multithread'а) от обычных глобальных переменных. Все требования по сериализации доступа так же применимы и к ним NB. Обычно при разделении одной переменной между потоками сериализацию применяют ИМЕННО к переменной, а не к потокам. Пример:
Можно написать С++ класс (указатель), который будет сериализовать доступ к объекту, который он содержит
Использование:
|
||||||||||
|
|||||||||||
Paspartu |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 67 Регистрация: 3.5.2007 Репутация: нет Всего: нет |
Конечно, про 32-х и 64-х битные процессоры... это, конечно, все интересно
![]() ![]() |
|||
|
||||
jonie |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 5613 Регистрация: 21.8.2005 Где: Владимир Репутация: 7 Всего: 118 |
xvr, хм, ладно убедили)
-------------------- Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет... |
|||
|
||||
Paspartu |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 67 Регистрация: 3.5.2007 Репутация: нет Всего: нет |
Ура!!!
![]() xvr, С-П-А-С-И-Б-О !!! К сожалению, у меня не достаточно прав, на увеличение Вашего рейтинга, и все что могу - это еще раз спасибо за разъясгегие!!! ![]() Добавлено позже Ура!!! ![]() xvr, С-П-А-С-И-Б-О !!! К сожалению, у меня не достаточно прав, на увеличение Вашего рейтинга, и все что могу - это еще раз спасибо за разъясгегие!!! ![]() Добавлено через 3 минуты и 28 секунд Еще раз всем спасибо! Многое для меня прояснилось! |
|||
|
||||
![]() ![]() ![]() |
Правила форума "C/C++: Системное программирование и WinAPI" | |
|
На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы . Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |