/// <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); } }