Console multithreading - c#

I'm trying read stdout byte stream into MemoryStream. All's works properly until I run same code in parallel threads
using (Process proc = new Process())
{
proc.StartInfo.FileName = eac3toFullPath;
proc.StartInfo.Arguments = "input.flac stdout.wav";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.Start();
proc.StandardOutput.BaseStream.CopyTo(mem);
proc.WaitForExit();
if (proc.ExitCode > 0)
{
throw new ConsoleAppException(proc);
}
mem.Position = 0;
}
Problem occurs when first thread execute stdout copy to mem and in the same time second thread report ExitCode equal '1'
I started console app (CLI) from WinForm application so where is no console window allocated due to CreateNoWindow = true;
So I repeat myself. The code works well, the ExitCode of CLI process is always zero,
until I run the code above multiple times simultaneously.
StandardOutput is redirected as of matter of fact I can't see any friendly error output. I also tried RedirectStandardError and ErrorDataReceived event and BeginErrorReadLine() with no luck.

Related

C# redirecting data to an already running console exe

What I want todo:
I want to start a built console application (AppB) from within another console application (AppA). AppA starts AppB without any arguments. All AppB does is to go into its Main() Method and call Console.ReadLine().
Now I want that AppA sends a string of data over to AppB's Console.ReadLine(). Is this even possibel? (I know I can send streams to a new Console.exe but that's not what I need.)
You need to use RedirectStandardInput:
Process myProcess = new Process();
myProcess.StartInfo.FileName = "someconsoleapp.exe";
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.StartInfo.ErrorDialog = false;
myProcess.Start();
StreamWriter stdInputWriter = myProcess.StandardInput;
StreamReader stdOutputReader = myProcess.StandardOutput;
stdInputWriter.WriteLine(password);
var op = stdOutputReader.ReadLine();
// close this - sending EOF to the console application - hopefully well written
// to handle this properly.
stdInputWriter.Close();
// Wait for the process to finish.
myProcess.WaitForExit();
myProcess.Close();

How to pass arguments to an already open terminal via System.Diagnostics.Process()

I have been messing around with triggering a bash script via C#. This all works fine when I first call the "open" command with arguments which in turn opens my .command script via Terminal.
Once the "open" command is used once Terminal or iTerm will remain open in the background, at which point calling the "open" command with arguments then has no further effect. I sadly have to manually quit the application to trigger my script again.
How can I pass arguments to an already open terminal application to restart my script without quitting?
I've searched online ad can't seem to work it out, it already took a good amount of time solve the opening code. Your help is much appreciated.
Here is the C# code I'm using to start the process:
var p = new System.Diagnostics.Process();
p.StartInfo.FileName = "open";
p.StartInfo.WorkingDirectory = installFolder;
p.StartInfo.Arguments = "/bin/bash --args \"open \"SomePath/Commands/myscript.command\"\"";
p.Start();
Thanks
EDIT:
Both answers were correct, this might help others:
ProcessStartInfo startInfo = new ProcessStartInfo("/bin/bash");
startInfo.WorkingDirectory = installFolder;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardOutput = true;
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
process.StandardInput.WriteLine("echo helloworld");
process.StandardInput.WriteLine("exit"); // if no exit then WaitForExit will lockup your program
process.StandardInput.Flush();
string line = process.StandardOutput.ReadLine();
while (line != null)
{
Debug.Log("line:" + line);
line = process.StandardOutput.ReadLine();
}
process.WaitForExit();
//process.Kill(); // already killed my console told me with an error
You can try:
before calling p.Start():
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
// for the process to take commands from you, not from the keyboard
and after:
if (p != null)
{
p.StandardInput.WriteLine("echo helloworld");
p.StandardInput.WriteLine("executable.exe arg1 arg2");
}
(taken from here)
This is what you may be looking for :
Gets a stream used to write the input of the application.
MSDN | Process.StandardInput Property
// This could do the trick
process.StandardInput.WriteLine("..");

Standard Output reader Hangs BCP tool

I was executing BCP command through exe and it stucks after copying 50000 rows.
I looked at some forums and got to know that if we use StandardOuputReader in code than its max limit of output is near to 50000 rows which is happening to me as well
Is there a way i ran redirect output where more than 50000 rows can get out.
This code works here i have
proc.StartInfo.RedirectStandardOutput = false;
but i want to have it as true, to see the outputs.
private static void RunBatch(string Fullfilepath, string BatchFilePathDumpFlatFile)
{
mLogger.Error("RunBatch Start=== >");
mLogger.Error("Batch Filepath " + Fullfilepath + '\n' + "Batch File Directory " + BatchFilePathDumpFlatFile);
Process proc = null;
string targetDir = BatchFilePathDumpFlatFile;
proc = new Process();
proc.StartInfo.WorkingDirectory = targetDir;
proc.StartInfo.FileName = Fullfilepath;
//proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.Arguments = "/c";
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardOutput = false;
proc.Start();
proc.WaitForExit();
string output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
string error = proc.StandardError.ReadToEnd();
proc.WaitForExit();
mLogger.Error("Output from batch " + output);
mLogger.Error("Error From Batch " + error);
}
update 1:
private static void RunBatch(string Fullfilepath, string BatchFilePathDumpFlatFile)
{
mLogger.Error("RunBatch Start=== >");
mLogger.Error("Batch Filepath " + Fullfilepath + '\n' + "Batch File Directory " + BatchFilePathDumpFlatFile);
Process proc = null;
string targetDir = BatchFilePathDumpFlatFile;
proc = new Process();
proc.StartInfo.WorkingDirectory = targetDir;
proc.StartInfo.FileName = Fullfilepath;
//proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.Arguments = "/c";
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.Start();
string output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
string error = proc.StandardError.ReadToEnd();
proc.WaitForExit();
mLogger.Error("Output from batch " + output);
mLogger.Error("Error From Batch " + error);
}
this is what i am using is there a mistake because still BCP hangs and it starts running when i stop the exe of the code.
This is the classic deadlock condition. You should not call WaitForExit before reading the StandardOutput fully.
When the output is redirected, process will not terminate before all of its StandardOutput stream is read. So calling WaitForExit will wait for the started process to terminate, and child process will wait for the parent process to read the output stream fully before it can finish and thus deadlocks.
Msdn provides the explanation and code sample to avoid deadlock.
Synchronous read operations introduce a dependency between the caller reading from the StandardOutput stream and the child process writing to that stream. These dependencies can result in deadlock conditions. When the caller reads from the redirected stream of a child process, it is dependent on the child. The caller waits on the read operation until the child writes to the stream or closes the stream. When the child process writes enough data to fill its redirected stream, it is dependent on the parent. The child process waits on the next write operation until the parent reads from the full stream or closes the stream. The deadlock condition results when the caller and child process wait on each other to complete an operation, and neither can proceed. You can avoid deadlocks by evaluating dependencies between the caller and child process.
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "Write500Lines.exe";
p.Start();
// Do not wait for the child process to exit before
// reading to the end of its redirected stream.
// p.WaitForExit();
// Read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
The code example avoids a deadlock condition by calling p.StandardOutput.ReadToEnd before p.WaitForExit. A deadlock condition can result if the parent process calls p.WaitForExit before p.StandardOutput.ReadToEnd and the child process writes enough text to fill the redirected stream. The parent process would wait indefinitely for the child process to exit. The child process would wait indefinitely for the parent to read from the full StandardOutput stream.
There is a similar issue when you read all text from both the standard output and standard error streams. The following C# code, for example, performs a read operation on both streams.
// Do not perform a synchronous read to the end of both
// redirected streams.
// string output = p.StandardOutput.ReadToEnd();
// string error = p.StandardError.ReadToEnd();
// p.WaitForExit();
// Use asynchronous read operations on at least one of the streams.
p.BeginOutputReadLine();
string error = p.StandardError.ReadToEnd();
p.WaitForExit();
Almost everything above taken from msdn, I suggest you read it fully to avoid creating deadlocks further.

Git Pull from Batch file with different user

I have a user, let's call it "MyUser". It has a password, suppose it is "Password". This user has an SSH key for git. I try to run from my ASP.NET application a batch file which issues git commands, it is at a location which is passed as a parameter. My function is as follows:
private void ExecuteCommand(string path, int timeout)
{
Process process = new Process();
process.StartInfo = new ProcessStartInfo();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "\"" + path + "\"";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
//processInfo.WorkingDirectory = Config.GitHubRepoPath;
process.StartInfo.UserName = "MyUser";
process.StartInfo.Password = new System.Security.SecureString();
process.StartInfo.Password.AppendChar('P');
process.StartInfo.Password.AppendChar('a');
process.StartInfo.Password.AppendChar('s');
process.StartInfo.Password.AppendChar('s');
process.StartInfo.Password.AppendChar('w');
process.StartInfo.Password.AppendChar('o');
process.StartInfo.Password.AppendChar('r');
process.StartInfo.Password.AppendChar('d');
// *** Redirect the output ***
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
process.Start();
// *** Read the streams ***
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
if (timeout <= 0)
{
process.WaitForExit();
}
else
{
process.WaitForExit(timeout);
}
int exitCode = process.ExitCode;
process.Close();
return new ShellCommandReturn { Error = error, ExitCode = exitCode, Output = output };
}
But when I run this function, the ExitCode is -1073741502 and error and output are empty. How can I fix this behavior?
Please help me, I have tried to solve this literally for days.
I think redirecting both standard error and standard output & attempts to consume both synchronously is wrong. Please see this link:
http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput%28v=vs.100%29.aspx
Allow me to copy excerpt:
A deadlock condition results if the parent process calls p.StandardOutput.ReadToEnd followed by p.StandardError.ReadToEnd and the child process writes enough text to fill its error stream. The parent process would wait indefinitely for the child process to close its StandardOutput stream. The child process would wait indefinitely for the parent to read from the full StandardError stream.
The other thing is ... when you invoke a cmd.exe instance, try adding a "/c" argument too.

C# Process StandardOutput.ReadLine returns the wanted output, but this is erased with no reason

System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.FileName="id";
proc.StartInfo.Arguments="-un";
proc.Start();
string nome_user = proc.StandardOutput.ReadLine();
proc.WaitForExit();
Hi, I was trying to run a shell command using Mono GTK#. When the debugger is on the proc.Start(); line, proc.StandardOutput.ReadLine() added to watch shows the output correctly, but when the debugger jumps to the next line (string nome_user = proc.StandardOutput.ReadLine();), with no reason the value of the proc.StandardOutput.ReadLine() turns into null. Can you help me?
Well, if you read it in the debugger, it's already been consumed from the stream. The stream won't magically rewind so it can be read again.

Categories