30

いくつかのコンテンツを取得して何かを実行するために、svn.exe の周りに簡単で汚いラッパーを書きましたが、特定の入力に対して、時折、再現可能にハングし、終了しません。たとえば、1 つの呼び出しは svn list に対するものです。

svn list "http://myserver:84/svn/Documents/Instruments/" --xml  --no-auth-cache --username myuser --password mypassword

このコマンド ラインは、コマンド シェルから実行すると正常に動作しますが、アプリでハングします。これを実行する私の c# コードは次のとおりです。

string cmd = "svn.exe";
string arguments = "list \"http://myserver:84/svn/Documents/Instruments/\" --xml  --no-auth-cache --username myuser --password mypassword";
int ms = 5000;
ProcessStartInfo psi = new ProcessStartInfo(cmd);
psi.Arguments = arguments;
psi.RedirectStandardOutput = true;
psi.WindowStyle = ProcessWindowStyle.Normal;
psi.UseShellExecute = false;
Process proc = Process.Start(psi);
StreamReader output = new StreamReader(proc.StandardOutput.BaseStream, Encoding.UTF8);

proc.WaitForExit(ms);
if (proc.HasExited)
{
    return output.ReadToEnd();
}

これには 5000 ミリ秒かかり、決して終了しません。時間を延ばしてもダメ。別のコマンド プロンプトでは、すぐに実行されるので、待ち時間の不足とは無関係であると確信しています。ただし、他の入力については、これでうまくいくようです。

また、ここで別の cmd.exe を実行しようとしました (exe は svn.exe で、args は元の引数文字列です) が、それでもハングが発生しました。

string cmd = "cmd";
string arguments = "/S /C \"" + exe + " " + args + "\"";

ここで何を台無しにすることができますか?また、この外部プロセスのものをどのようにデバッグできますか?

編集:

私は今、これに対処しようとしています。ムーチョは、Jon Skeet の提案に感謝します。ただし、私はマルチスレッドの初心者なので、これを処理する方法について別の質問があります。明らかな欠陥やその他のばかげたことを改善するための提案が欲しい. 最終的に、stdout ストリーム、出力を保持する StringBuilder、および終了を通知するフラグを含む小さなクラスを作成しました。次に、ThreadPool.QueueUserWorkItem を使用して、クラスのインスタンスを渡しました。

ProcessBufferHandler bufferHandler = new ProcessBufferHandler(proc.StandardOutput.BaseStream,
                                                                          Encoding.UTF8);
ThreadPool.QueueUserWorkItem(ProcessStream, bufferHandler);

proc.WaitForExit(ms);
if (proc.HasExited)
{
    bufferHandler.Stop();
    return bufferHandler.ReadToEnd();
}

... と ...

private class ProcessBufferHandler
{
    public Stream stream;
    public StringBuilder sb;
    public Encoding encoding;
    public State state;

    public enum State
    {
        Running,
        Stopped
    }

    public ProcessBufferHandler(Stream stream, Encoding encoding)
    {
        this.stream = stream;
        this.sb = new StringBuilder();
        this.encoding = encoding;
        state = State.Running;
    }
    public void ProcessBuffer()
    {
        sb.Append(new StreamReader(stream, encoding).ReadToEnd());
    }

    public string ReadToEnd()
    {
        return sb.ToString();
    }

    public void Stop()
    {
        state = State.Stopped;
    }
}

これは機能しているように見えますが、これが最善の方法であるかどうかは疑わしいです。これは合理的ですか?そして、それを改善するにはどうすればよいですか?

4

6 に答える 6

41

標準的な問題の 1 つ: プロセスは、ユーザーがその出力を読み取るのを待っている可能性があります。終了するのを待っている間に標準出力から読み取る別のスレッドを作成します。少し面倒ですが、それが問題なのかもしれません。

于 2009-01-13T16:19:09.860 に答える
4

クライアントのマシンに exe をドロップし、Process.Start を使用してそれを起動する必要がありました。

呼び出し元のアプリケーションがハングします。問題は、exe が危険であり、他のアプリケーションがそれを起動できないと想定しているマシンでした。

exeを右クリックして、プロパティに移動します。セキュリティ警告の横にある下部に向かって「ブロックを解除」を押します。

ここに画像の説明を入力

于 2018-08-13T18:42:48.027 に答える
1

これは古い投稿であることは知っていますが、おそらくこれは誰かを助けるでしょう. これを使用して、.Net TPL タスクを使用していくつかの AWS (Amazon Web Services) CLI コマンドを実行しました。

bgwRun_DoWorkでループを保持するWinFormバックグラウンドワーカーメソッド内で作成された.Net TPLタスク内で実行されるコマンド実行で、このようなことを行いましwhile(!bgwRun.CancellationPending)た。これには、.Net ThreadPool クラスを使用した新しいスレッドを介したプロセスからの標準出力の読み取りが含まれます。

private void bgwRun_DoWork(object sender, DoWorkEventArgs e)
{
  while (!bgwRun.CancellationPending)
  {
   //build TPL Tasks
   var tasks = new List<Task>();

   //work to add tasks here

   tasks.Add(new Task(()=>{

     //build .Net ProcessInfo, Process and start Process here

     ThreadPool.QueueUserWorkItem(state =>
       {
           while (!process.StandardOutput.EndOfStream)
           {
               var output = process.StandardOutput.ReadLine();
               if (!string.IsNullOrEmpty(output))
               {
                   bgwRun_ProgressChanged(this, new ProgressChangedEventArgs(0, new ExecutionInfo
                   {
                       Type = "ExecutionInfo",
                       Text = output,
                       Configuration = s3SyncConfiguration
                   }));
               }

               if (cancellationToken.GetValueOrDefault().IsCancellationRequested)
               {
                     break;
               }
           }
       });
   });//work Task

   //loop through and start tasks here and handle completed tasks

  } //end while
}
于 2016-04-28T15:05:31.480 に答える
0

SVN リポジトリの実行が遅い場合があることはわかっているので、5 秒では足りないのではないでしょうか? ブレークポイントからプロセスに渡す文字列をコピーしたので、何も要求されていませんか?

于 2009-01-13T16:21:14.457 に答える