We compile the code from the code to play the race of two processes

- execution of code given by users, as on ideone.com,
- "Well, you never know why," and
- “And this is a separate issue”
Today we use this class to conveniently reproduce the race of two processes.
There is the following code, which is provided here only to illustrate the use case:
Process process = …;
process.Run();
//blahblahblahif (!process.WaitForExit(sometime))
{
process.Kill();
}
and it turns out that if the process ends after returning from WaitForExit (), but before the start of the Kill () substantive work, the latter throws an InvalidOperationException with the message "no way, the process has already completed." Yes, indeed it is sometimes repeated. This is a typical race.
There is a desire to report this as an error (in this case, we assume that the “correct” behavior of Kill () in this case is to do nothing).
The first (leading) process will execute this code:
var process = new Process();
process.StartInfo.FileName = secondExeName;
process.Start();
if (!process.WaitForExit(900))
{
System.Threading.Thread.Sleep(500);
process.Kill();
}
second (slave) - this code:
System.Threading.Thread.Sleep( 1000 );
The values of the constants are selected so that the race always develops in the right way and leads to the throwing of an exception.
It remains only to
The obvious way:
- make a solution with two projects like Console Application,
- specify the assembly order,
- choose a lead process project as a starting one,
- write the relative path to the executable file of the slave process, ...
TL; DR ;, anyway, the one who opens the solution will have the wrong version of Visual Studio, so either after the conversion one of the settings will be lost, or the project simply won’t open because it “requires a newer version”. Even if the version is the same, the senseless exercise of opening the archive and unpacking it into the next folder will not add joy to all those who will run this code (be sure that you have to open and run the same code to parse and evaluate one error message many people). Finally, it is extremely cynical to demand downloading and opening an archive, just to read a few dozen lines of code.
Therefore, we use a compilation of code from the code to get one program that does everything necessary to reproduce the development of the race we need.
using System;
using System.Linq;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Diagnostics;
namespaceConsoleApplicationNPlusOne
{
classProgram
{
staticvoidMain(string[] args)
{
var secondExecutableName = "GuidedProcess.png";
compileGuidedExecutable(secondExecutableName);
using (var guidedProcess = new Process())
{
guidedProcess.StartInfo.FileName = secondExecutableName;
guidedProcess.StartInfo.UseShellExecute = false;
guidedProcess.Start();
if (!guidedProcess.WaitForExit(900))
{
System.Threading.Thread.Sleep(500);
guidedProcess.Kill();
}
}
}
staticvoidcompileGuidedExecutable(string filePath)
{
using (var compiler = new CSharpCodeProvider())
{
var parameters = new CompilerParameters(null, filePath, true);
parameters.GenerateExecutable = true;
var compilationResult = compiler.CompileAssemblyFromSource(
parameters, guidedProcessCode);
var compilationErrors = compilationResult.Errors;
if (compilationErrors.HasErrors)
{
var firstError = compilationErrors.Cast<CompilerError>().First();
thrownew InvalidOperationException(String.Format(
"Compilation failed. Line {0}: {1}", firstError.Line, firstError.ErrorText));
}
}
}
staticreadonly String guidedProcessCode =
@"class Program {
public static void Main(string[] args)
{
System.Threading.Thread.Sleep( 1000 );
}
}";
}
}
The code of both processes is neatly folded together, it can be thoughtlessly copied into the just created empty Console Application project and pressed F5 in Visual Studio, or you can try to compile and execute it in your mind.
This was another example of using CSharpCodeProvider and compiling code from code.
Dmitry Meshcheryakov,
product department for developers