next up previous contents
Next: Разъяснения Up: MPI и треды Previous: MPI и треды   Contents

Основы

В тредо-безопасной реализации, процесс MPI - процесс, который может быть многопоточным. Каждый тред может производить вызовы MPI; однако, треды адресуемы не отдельно: ранг в посылающем или принимающем вызове идентифицирует процесс, а не тред. Сообщение, посланное процессу может быть получено любым тредом в этом процессе.

Объяснение: Эта модель соответствует модели межпроцессорной связи POSIX: факт, что процесс является многопоточным, а не однопоточным, не затрагивает внешний интерфейс этого процесса. Реализации MPI, где MPI ``процессы'' - треды POSIX внутри одного процесса POSIX, не являются тредо-безопасными по этому определению (действительно, их ``процессы'' - однопоточны). []

Совет пользователям: Ответственность пользователя - предотвратить гонки, когда треды в пределах того же самого приложения посылают противоречивые вызовы связи. Пользователь может удостовериться, что два треда в одном и том же процессе не будут выдавать противоречивые вызовы связи, используя различные коммуникаторы в каждом треде. []

Два основных требования для тредо-безопасной реализации перечислены ниже.

  1. Все вызовы MPI тредо-безопасны. То есть два одновременно выполняющихся треда могут делать вызовы MPI, и результат будет таким, как будто вызовы выполнены в некотором порядке, даже если их выполнение одновременно.
  2. Блокирующие вызовы MPI блокируют только вызывающий тред, позволяя другому треду выполниться, если доступно. Вызывающий тред будет блокирован, пока не произойдет событие, которое он ожидает. Как только блокированная связь разрешается и может продолжаться, тогда вызов завершится, и тред будет отмечен как runnable (готовый к выполнению), в пределах конечного времени. Блокированный тред не будет предотвращать продвижение других runnable-тредов в том же самом процессе, и не будет предотвращать их от выполняющихся вызовов MPI.

Пример 8.3 Процесс 0 состоит из двух тредов. Первый тред выполняет блокирующий вызов послать MPI_Send(buff1, count, type, 0, 0, comm), принимая во внимание, что второй тред выполняет блокирующий вызов получить MPI_Recv(buff2, count, type, 0, 0, comm, &status). То есть первый тред посылает сообщение, которое получено вторым тредом. Эта связь должна всегда достигнуть цели. Согласно первому требованию, выполнение будет соответствовать некоторому чередованию из двух вызовов. Согласно второму требованию, вызов MPI может только блокировать вызывающий тред и не должен предотвращать продвижение другого треда. Если посылающий вызов произошел перед получающим вызовом, то посылающий тред может блокировать, но это не будет предотвращать получающий тред от выполнения. Таким образом, получающий вызов произойдет. Как только оба вызова происходят, связь допускается, и оба вызова завершатся. С другой стороны, однопоточный процесс, который передает послать, сопровождается соответствующим получить, может блокироваться. Требование продвижения для многопоточных реализаций более сильное, поскольку блокированный вызов не может предотвращать продвижение других тредов.

Совет разработчикам: Вызовы MPI могут быть сделаны тредо-безопасными, выполняясь
только по одному, например, защищая код MPI одной процессо-глобальной блокировкой. Однако, блокированные операции не могут проводить блокировку, поскольку это предотвратило бы продвижение других тредов в процессе. Блокировка проводится только на время локально-атомарной завершающей подоперации типа регистрации посылающего или завершения посылающего, и выполняется между ними. Более тонкие блокировки могут обеспечить большее параллелизма, за счет высоких накладных расходов блокировки. Параллелизм может также быть достигнут при наличии части протокола MPI, выполненного отдельными тредами сервера. []



Alex Otwagin 2002-12-10