提问人:Pietro di Caprio 提问时间:7/18/2018 最后编辑:Panagiotis KanavosPietro di Caprio 更新时间:7/25/2018 访问量:1108
启动多个进程并异步重定向输出
Start multiple process and redirect output async
问:
我正在用一些对我来说很困难的事情来挑战自己。
我想要一个运行“从属终端”的“主终端”。 从站使用“重定向输出”选项 (RedirectStandardOutput) 启动。 从站必须异步运行,主站应从站管理“ReadLine”。 当从站运行时,主站必须能够执行其他操作。
我的实际代码:
static void StartTerminal(string ExecPath, int DefaultPort, string Arguments = "")
{
int port = DefaultPort;
if (usedPorts.Contains(port)) port = nextPort;
while(usedPorts.Contains(nextPort))
{
nextPort++;
port = nextPort;
}
usedPorts.Add(port);
string _arguments = "/port:" + port;
_arguments += Arguments;
//* Create your Process
Process process = new Process();
process.StartInfo.FileName = "dotnet ";
process.StartInfo.Arguments = ExecPath + " /c " + _arguments;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
//* Set your output and error (asynchronous) handlers
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
process.ErrorDataReceived += new DataReceivedEventHandler(OutErrorHandler);
//* Start process and handlers
ThreadStart ths = new ThreadStart(() => {
bool ret = process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
});
Thread th = new Thread(ths);
th.Start();
//process.Start();
//process.BeginOutputReadLine();
//process.BeginErrorReadLine();
//process.WaitForExit();
}
如您所见,我尝试了启动和不启动新线程。 线程似乎很好,我在从属终端完成操作之前到达了主空的末尾,但随后我在从属终端的“ReadLine”请求中被阻止。用户必须按Enter键才能继续,我不想要这个。
你能帮帮我吗? 你建议采取不同的方法吗?
谢谢,问候。
编辑1:我想管理从属终端等待“Enter”的情况,因为它可能由第三方开发,这些第三方可能会忽略我说不使用的指南(好吧,这不是我的问题,但我喜欢愚蠢的证明软件)。
主终端管理着数量不明的从属终端,并记录从站的所有输出,并运行一个看门狗,如果从站崩溃,该看门狗会重新启动它。
主站还接收启动/停止/重启从站的命令和/或其他命令。Console.ReadLine()
答:
根据 Process Class 文档,两者都 和 execute,这意味着它们不会阻止程序执行(或者换句话说:程序不会等待这些方法完成执行)。Process.BeginOutputReadLine();
Process.BeginErrorReadLine();
asynchronously
您可能希望设置一些布尔值来指示数据何时完成读入和事件处理程序,并在 main 方法中添加一个循环,该循环在执行两个方法之前不允许程序完成。OutputDataReceived
ErrorDataReceived
private void DataReceivedEventHandler( [parameters] ){
//I believe this is the part where you read the actual stream
outputDataReceived = true;
}//do the same for ErrorDataReceived
while (!outputDataReceived && !errorDataReceived){
wait(1000); //The actual method might be different, maybe sleep( 1000 ) or thread.sleep ( you can also set a different interval )
}
编辑(删除了不相关的编辑):异步任务、任务和并行执行在此问题的答案中进行了描述。我相信任何一个答案都会满足您的需求。
基本上,在链接问题的答案中使用任何代码示例,只需在线程/任务/并行调用中调用您的方法即可。使用答案中的代码创建异步处理并实现逻辑,以防止程序到达其末尾,直到所有线程完成其工作。伪代码:StartTerminal( )
List<Thread> threads = new List<Thread>();
private void StartTerminal(int id, params){
//all of your code keep it asynchornous
while( !outputDataReceived && !errorDataReceived ){
sleep( 1000 ); //delay between checks
} //Makes sure this thread does not close until data is received, implement any other logic that should keep the thread alive here
}
public static void main(...){
foreach(ParameterSet params in Parameters){ //Create thread list with different parameters
var thread = new Thread( StartTerminal(params) );
threads.Add( thread );
}
while( !threads.isEmpty() ) ){ //if it is empty, all threads finished the job and got deleted, loop is skipped and program closes
var threadsToRemove = new List<Thread>();
foreach(Thread t in threads){ //start unstarted threads
if(t.ThreadState == ThreadState.Unstarted){
threads[i].Start( ).
}elseif(t.ThreadState == ThreadState.Stopped){ //remove stopped threads
threadsToRemove.Add(t).
}//Implement other logic for suspended, aborted and other threads...
}
foreach(Thread t in threadsToRemove){
threads.Remove(t);
}
sleep(1000); //delay between checks
}
}
编辑2:将这些模式交给你的从属终端开发人员(如果他们不知道如何自己做,而不是阻止所有内容),因为一旦同步调用“ReadLine”,在用户按回车键之前,你什么也做不了(合理)。
如果可能(尤其是在对硬件进行编程时,例如控制器),请使用触发器而不是“ReadLines”进行用户输入
HardwareButtonEnter.Press += delegate{ userInput = eventParameters.userInput;
UserInputReceived = true;}; //This is really hardware API specific code, only the boolean is important
//start an async thread/process for reading master terminal input.
while(1 = 1){
if(UserInputReceived){
ProcessUserInput().
}elseif(masterTerminalDataReceived){
ProcessMasterTerminalData().
}
}
如果无法使用触发器(例如,在对控制台应用程序进行编程时),请将阻塞语句放在异步线程中,并在线程完成时处理它们。
//Start your (async) ReadLine thread. Make sure it also sets UserInputReceived = true when it ends
//Start your async process read thread. also get it to set some boolean.
while( 1 = 1){
if(threads.Any( t => t.Status = Finished ){
if(UserInputReceived){
}elseif(terminalInputReceived){
..
}
}
}
评论
StartTerminal([params]);
Console.ReadLine()
process.WaitForExit();
System.Threading.ThreadState.WaitSleepJoin
thread.Interrupt()
评论
StartTerminal
ReadLine
StartTerminal( ... )
process.Start()
Parallel.ForEach()