我正在挑战自己对我来说很困难的东西。
我想要一个运行“从属终端”的“主终端”。 从站通过“重定向输出”选项(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();
}
如您所见,无论是否启动新线程,我都尝试过。 在线程看起来不错的情况下,我在从属终端完成操作之前到达Main void的末尾,但随后我受从属的“ ReadLine”请求而被阻止。用户必须按Enter才能继续,我不希望这样做。
能帮我吗? 您是否建议其他方法?
谢谢。
修改1:
我想管理从属终端正在等待“ Enter”的情况,因为它可能由第三方开发,可能会忽略我说不使用Console.ReadLine()
的准则(好吧,这不是我的问题,但是我喜欢愚蠢的证明软件)。
主终端管理着未定义数量的从终端,并记录了从终端的所有输出,并运行了一个看门狗,如果它崩溃,它将重启从终端。
主服务器还接收启动/停止/重启从设备的命令和/或其他命令。
答案 0 :(得分:2)
根据Process Class文档,Process.BeginOutputReadLine();
和Process.BeginErrorReadLine();
都执行asynchronously
,这意味着它们不会阻止程序执行(换句话说:程序不会等待这些方法执行完毕。
您可能想设置一些布尔值,以指示何时在OutputDataReceived
和ErrorDataReceived
事件处理程序中完成数据读取,并在main方法中添加一个循环,直到两个方法都被执行时,该循环才允许程序完成被执行。
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 )
}
编辑(删除了无关紧要的内容): Asynchronous tasks,treads and Parallel execution在此问题的答案中有所描述。我相信任何一种答案都可以满足您的需求。
基本上,在链接的问题的答案中使用任何代码示例,只需在线程/任务/并行调用中调用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”,在用户按Enter之前,您无法做任何(合理的)操作。
在可能的情况下(尤其是在对诸如控制器之类的硬件进行编程时)使用触发器代替“ 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){
..
}
}
}