
The CSharpCodeProvider class allows a C # program to compile a C # code. The usual question is why. The usual answers:
- Execution of the code given by users, as on ideone.com,
- “Well, why don't you know?” And
- "And this is a separate question"
Today we use this class to easily reproduce the race of the two processes.
There is the following code, which is given here
only to illustrate the use case:
Process process = …; process.Run(); //blahblahblah if (!process.WaitForExit(sometime)) { process.Kill(); }
and it turns out that if the process terminates after returning from WaitForExit (), but before the Kill () starts to be meaningful, the latter throws an InvalidOperationException with the message "no way, the process has already ended."
Yes, it does indeed sometimes repeat. This is a typical race.
')
There is a desire to report this as an error (in this case we will assume that the “correct” Kill () behavior in this case is to do nothing).
EXTREMELY UNEXPECTED Naturally, we will be asked to code to reproduce this situation. We need to do two processes that would reliably reproduce just such a development of the race, which leads to the "wrong" behavior.
The first (leading) process will execute the following code:
var process = new Process(); process.StartInfo.FileName = secondExeName; process.Start(); if (!process.WaitForExit(900)) { System.Threading.Thread.Sleep(500); process.Kill(); }
the second (slave) is such a code:
System.Threading.Thread.Sleep( 1000 );
The values ​​of the constants are chosen in such a way that the race always develops in the right way and leads to the release of an exception.
It remains only to
fasten the monitor to make an example of this that would be convenient to run.
The obvious way is:
- make a solution with two projects of the Console Application type,
- specify the assembly order
- select the project leading process as a start,
- set 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 conversion one of the settings will be lost, or the project simply will not open, as “it requires a newer version”. Even if the version is the same, a meaningless exercise of opening the archive and unpacking it into the next folder will not add joy to all those who run this code (you can be sure that you have to open and run the same code to analyze and evaluate one error message many people). Finally, it is extremely cynical to demand downloading and opening the archive in order to simply read a few dozen lines of code.
Therefore, we use code compilation from 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; namespace ConsoleApplicationNPlusOne { class Program { static void Main(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(); } } } static void compileGuidedExecutable(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(); throw new InvalidOperationException(String.Format( "Compilation failed. Line {0}: {1}", firstError.Line, firstError.ErrorText)); } } } static readonly 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 newly created empty Console Application project and click 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 Mescheryakov,
product department for developers