Изучаю многопоточное программирование, с событиями, мьютексами вроде разобрался. Такой вопрос: Что будет, если два и более потока вызовут функцию, которая находится вне потоков, она как бы глобальная. Например, strlen() или какую нибудь другую функцию пользователя. И что будет, если в ней будут использоваться какие то свои локальные переменные? Не будет ли какой-то пакости?
Ничего не будет. У кажд. потока свой стек. лишь бы глобальными не пользовалась, а то без синххронизации никак.
asmfan это точно? Известно что потоки используют единое адресное пространство. К глобальным переменным я обращаюсь через мьютексы. А как дело обстоит с глобальными функциями? функции, которые имеют один и тот же адрес. Как происходит работа в ней, когда ее вызывают сразу несколько потоков?
beginner В Visual Studio "зачем-то" две версии библиотек - просто и мультипоточная. Соответственно и пользовательские функции должны быть двух видов, если необходимо.
beginner Синхронизация нужна только для изменяемых данных. Функция это просто кусок неизменяемой памяти, в котором записан код. Если в функции не используются глобальные переменные, то разные ядра\процы могут параллельно считывать из памяти и исполнять один и тот же кусок кода, т.к. у каждого потока своя собственная область стека. Т.е. код функции один и тот же, а адреса локальных переменных, копий регистров (push\pop) и адреса возврата у каждого потока свои
Функция сама по себе -- это просто набор байтов в памяти. Вне потока она не исполняется, т.е. как бы не существует Так что "внепоточных функций" быть не может. Проблема в другом: если некая функция может быть вызвана повторно до того, как её первое выполнение полностью завершится, она должна быть повторно-входимой (реентерабельной). Чтобы она удовлетворяла этому требованию, надо соблюдать несколько простых правил, из которых важнейшие -- не изменять собственный код (при программировании на ЯВУ это всегда так) и использовать на запись только локальные переменные (в том числе значения параметров, переданных ей через адреса), но ни в коем случае не глобальные переменные. Синхронизация же к одновременному выполнению одной и той же функции прямого отношения не имеет.
leo ОООООО, я подобный ответ хотел услышать! т.е. получается, когда поток вызывает внешнюю общую функцию, для него даже не важно что она общая. Правильно? Забегая наперед, хочу еще спросить: Что будет, если в этой глобальной функции будет обращение к какой то глобальной переменной, ессно через средства синхронизации, мютекс или событие - не столь важно. Другие потоки, которые вызовут эту функцию, когда дойдут до обращения к этой глобальной переменной - приостановятся и будут ждать пока переменная освободится для использования? Если несколько потоков обратятся - будет ли создана какая то очередь по доступу к этой переменной? Типа поток 1 первый обратился к переменой - он и первый получит доступ, поток 2 - вторым обратился и второй получит доступ. Так ли это на самом деле? Заранее спасибо тебе и всем людям, которые помогают в этом нелегком деле - программировании valterg Я почему то всю жизнь думал, что в студии две версии библиотек: релиз и дебаг... Блин я не успеваю формулировать новые вопросы, как уже практически отвечают на них Очень классный форум, ответ на вопрос можно получить практически сразу, что очень радует. И не просто ответ, а очень квалифицированный ответ! I'm happy! SII Получается что если нельзя использовать глобальную переменную в таких функциях, то можно поступить следующим образом: сохранить эту глобальную переменную в какую нибудь временную, и уже ее передать некой функции для обработки. А по возращении результата - сохранить ее обратно в глобальную, используя средства синхронизации. Мне кажется в этом случае проблем с глобальными переменными вообще не будет, но хочется узнать что получится, если использовать метод, который я выше описал? Спасибо.
Зависит от средств синхронизации 4 как минимум: single-thread debug, single-thread release, multi-thread debug, multi-thread release
самый лучший способ обеспечить реентерабельность - использовать per-cpu/TLS/атомарные данные, а не синхронизацию
если размер переменной будет больше максимального размера операнда какой-либо атомарной инструкции, при сохранении тоже понадобится синхронизация
rei3er про атомарные данные вообще в первый раз слышу... при сохранении ессно будет синхронизация... я просто не дописал, спасибо
не так выразился данные, которые могут целиком использоваться в качестве операндов атомарных инструкций
beginner rei3er Уж сразу бы пояснили про атомарные инструкции В общем, такие инструкции, которые, обращаясь к данным, полностью блокируют занимаемую ими область памяти на всё время доступа. Всегда такой является инструкция XCHG -- пока она считывает из памяти старое значение некоей переменной и записывает новое, доступ к памяти блокирован, поэтому есть гарантия, что никакой потусторонний поток, даже выполняемый на другом процессоре многопроцессорной системы, вклиниться в этот процесс не сможет. Ряд других инструкций могут быть сделаны атомарными с помощью префикса LOCK. Подробно всё расписано в интеловских мануалах. Однако на ЯВУ надо разбираться, как этот самый атомарный доступ выполнять. Лично я Си практически не использую, поэтому понятия не имею, ну а на Паскале (Дельфи) я привык все такие вещи делать с помощью ассемблерных вставок. Что же касается синхронизации, то всегда следует помнить о возможности возникновения взаимоблокировки. Если процесс 1 захватил блокировку А и пытается захватить блокировку Б, а процесс 2 захватил блокировку Б и пытается захватить блокировку А, они повисли намертво -- это состояние, именуемое дедлоком (deadlock). Чтобы такого не происходило, необходимо предусмотреть определённую очерёдность захвата блокировок -- это не слишком сложно (я б даже сказал, совсем не сложно), но к этому нужно привыкнуть
beginner Тебе стоит прочитать Джеффри РИХТЕР "Создание эффективных WIN32-приложений с учетом специфики 64-разрядной версии Windows" Там про синхронизацию(и про много что ещё) подробно расписано.
инструкция, обеспечивающая целостность своих операндов (названных "атомарные данные"), которая выполняется без выделения тактов процессора другим инструкциям. P.S. это определение можно расширить и спроецировать на синхронизацию, где для создания "атомарных данных" вводятся дополнительные переменные. т.е. "безопасный поток" - поток, обеспечивающий целостность своих данных при переключении контекста.
тогда уж для полноты картины стоит добавить, что чтение/запись (mov) 1 байта всегда атомарны также атомарны чтение/запись 2, 4, 8 (на 64-х разрядных системах) байт по адресам, кратным соответственно 2-ум, 4-м и 8-ми в GCC есть набор built-in функций типа __sync_bool_compare_and_swap() __sync_fetch_and_add() и т. д
asd Спасибо, уже скачал, осваиваю!!! Увы атомарные инструкции наврядли будут доступны, так как общими переменными являются структуры. Делаю только через синхронизацию. Счас пока разбираюсь, вопросов много, но все они решаемы после прочтения статей/книг. Главное что можно запустить одну и ту же функцию из разных потоков - это то что мне нужно было!!