Exemplo n.º 1
0
        /// <summary>Initializes the MPI environment.</summary>
        /// <param name="args">
        ///   Arguments passed to the <c>Main</c> function in your program. MPI
        ///   may use some of these arguments for its initialization, and will remove
        ///   them from this argument before returning.
        /// </param>
        /// <param name="threading">
        ///   The level of threading support requested of the MPI implementation. The
        ///   implementation will attempt to provide this level of threading support.
        ///   However, the actual level of threading support provided will be published
        ///   via the <see cref="MPI.Environment.Threading"/> property.
        /// </param>
        /// <remarks>
        ///   This routine must be invoked before using any other MPI facilities.
        ///   Be sure to call <c>Dispose()</c> to finalize the MPI environment before exiting!
        /// </remarks>
        /// <example>This simple program initializes MPI and writes out the rank of each processor:
        /// <code>
        /// using MPI;
        ///
        /// public class Hello
        /// {
        ///     static int Main(string[] args)
        ///     {
        ///         using (MPI.Environment env = new MPI.Environment(ref args))
        ///         {
        ///             System.Console.WriteLine("Hello, from process number "
        ///                 + MPI.Communicator.world.Rank.ToString() + " of "
        ///                 + MPI.Communicator.world.Size.ToString());
        ///         }
        ///     }
        /// }
        /// </code>
        /// </example>
        public Environment(ref string[] args, Threading threading)
        {
            if (Finalized)
            {
                throw new ObjectDisposedException("Constructor called when object already finalized.");
            }

            if (!Initialized)
            {
                int requiredThreadLevel = 0;
                int providedThreadLevel;

                switch (threading)
                {
                case Threading.Single:
                    requiredThreadLevel = Unsafe.MPI_THREAD_SINGLE;
                    break;

                case Threading.Funneled:
                    requiredThreadLevel = Unsafe.MPI_THREAD_FUNNELED;
                    break;

                case Threading.Serialized:
                    requiredThreadLevel = Unsafe.MPI_THREAD_SERIALIZED;
                    break;

                case Threading.Multiple:
                    requiredThreadLevel = Unsafe.MPI_THREAD_MULTIPLE;
                    break;
                }

                if (args == null)
                {
                    unsafe
                    {
                        int    argc = 0;
                        byte **argv = null;
                        Unsafe.MPI_Init_thread(ref argc, ref argv, requiredThreadLevel, out providedThreadLevel);
                    }
                }
                else
                {
                    ASCIIEncoding ascii = new ASCIIEncoding();
                    unsafe
                    {
                        // Copy args into C-style argc/argv
                        int    my_argc = args.Length;
                        byte **my_argv = stackalloc byte *[my_argc];
                        for (int argidx = 0; argidx < my_argc; ++argidx)
                        {
                            // Copy argument into a byte array (C-style characters)
                            char[] arg = args[argidx].ToCharArray();
                            fixed(char *argp = arg)
                            {
                                int   length = ascii.GetByteCount(arg);
                                byte *c_arg  = stackalloc byte[length];

                                if (length > 0)
                                {
                                    ascii.GetBytes(argp, arg.Length, c_arg, length);
                                }
                                my_argv[argidx] = c_arg;
                            }
                        }

                        // Initialize MPI
                        int    mpi_argc = my_argc;
                        byte **mpi_argv = my_argv;
                        Unsafe.MPI_Init_thread(ref mpi_argc, ref mpi_argv, requiredThreadLevel, out providedThreadLevel);

                        // \todo Copy c-style argc/argv back into args
                        if (mpi_argc != my_argc || mpi_argv != my_argv)
                        {
                            args = new string[mpi_argc];
                            for (int argidx = 0; argidx < args.Length; ++argidx)
                            {
                                // Find the end of the string
                                int byteCount = 0;
                                while (mpi_argv[argidx][byteCount] != 0)
                                {
                                    ++byteCount;
                                }

                                // Determine how many Unicode characters we need
                                int charCount = ascii.GetCharCount(mpi_argv[argidx], byteCount);

                                // Convert ASCII characters into unicode characters
                                char[] chars = new char[charCount];
                                fixed(char *argp = chars)
                                {
                                    ascii.GetChars(mpi_argv[argidx], byteCount, argp, charCount);
                                }

                                // Create the resulting string
                                args[argidx] = new string(chars);
                            }
                        }
                    }
                }

                switch (providedThreadLevel)
                {
                case Unsafe.MPI_THREAD_SINGLE:
                    Environment.providedThreadLevel = Threading.Single;
                    break;

                case Unsafe.MPI_THREAD_FUNNELED:
                    Environment.providedThreadLevel = Threading.Funneled;
                    break;

                case Unsafe.MPI_THREAD_SERIALIZED:
                    Environment.providedThreadLevel = Threading.Serialized;
                    break;

                case Unsafe.MPI_THREAD_MULTIPLE:
                    Environment.providedThreadLevel = Threading.Multiple;
                    break;

                default:
                    throw new ApplicationException("MPI.NET: Underlying MPI library returned incorrect value for thread level");
                }

                // Setup communicators
                Communicator.world = Intracommunicator.Adopt(Unsafe.MPI_COMM_WORLD);
                Communicator.self  = Intracommunicator.Adopt(Unsafe.MPI_COMM_SELF);
            }
        }