2010-01-18 38 views
6

Tôi đang làm việc với C# và gặp sự cố khi hiểu cách đọc stdout không đồng bộ từ quá trình con. Những gì tôi muốn làm là tạo ra một tiến trình con thực hiện một ứng dụng và sau đó trình bày bất cứ điều gì được nhận từ quá trình đó 'stdout trong một hộp văn bản. Tôi cần phải xem mọi nhân vật đầu ra từ tiến trình con ngay lập tức và không thể chờ đợi một dòng để hoàn thành, do đó tôi không nghĩ rằng sự kiện Process.OutputDataReceived phù hợp với mục đích của tôi. Bạn có thể cho tôi biết một cách lành mạnh để thực hiện điều này không?C# Đọc stdout của quá trình con không đồng bộ

Tôi đã thử gọi Process.StandardOutput.BaseStream.BeginRead() và chuyển chức năng gọi lại cho nó, nhưng trong chức năng gọi lại này, tôi nhận được ngoại lệ từ Process.StandardOutput.BaseStream.EndRead().

Mã của tôi trông như thế này (quá trình con là công cụ tập lệnh - viết tắt là "SE" - để xác minh chức năng của thiết bị bên ngoài. Kịch bản được thực thi theo thứ tự và mỗi tập lệnh yêu cầu một phiên bản của ứng dụng SE)

private bool startScript() 
{ 
    // Starts the currently indexed script 

    if (null != scriptList) 
    { 

    if (0 == scriptList.Count || scriptListIndexer == scriptList.Count) 
    { 
     // If indexer equals list count then there are no active scripts in 
     // the list or the last active script in the list has just finished 
     return false;        // ## RETURN ## 
    } 
    if (ScriptExecutionState.RUNNING == scriptList[scriptListIndexer].executionState) 
    { 
     return false;        // ## RETURN ## 
    } 

    if (0 == SE_Path.Length) 
    { 
     return false;        // ## RETURN ## 
    } 

    SE_Process = new Process(); 
    SE_Process.StartInfo.FileName = SE_Path; 
    SE_Process.StartInfo.CreateNoWindow = true; 
    SE_Process.StartInfo.UseShellExecute = false; 
    SE_Process.StartInfo.RedirectStandardError = true; 
    SE_Process.StartInfo.RedirectStandardOutput = true; 
    SE_Process.EnableRaisingEvents = true; 
    SE_Process.StartInfo.Arguments = scriptList[scriptListIndexer].getParameterString(); 

    // Subscribe to process exit event 
    SE_Process.Exited += new EventHandler(SE_Process_Exited); 

    try 
    { 
     if (SE_Process.Start()) 
     { 
     // Do stuff 
     } 
     else 
     { 
     // Do stuff 
     } 
    } 
    catch (Exception exc) 
    { 
     // Do stuff 
    } 

    // Assign 'read_SE_StdOut()' as call-back for the event of stdout-data from SE 
    SE_Process.StandardOutput.BaseStream.BeginRead(SE_StdOutBuffer, 0, SE_BUFFERSIZE, read_SE_StdOut, null); 

    return true;          // ## RETURN ## 

    } 
    else 
    { 
    return false;          // ## RETURN ## 
    } 
} 

private void read_SE_StdOut(IAsyncResult result) 
{ 
    try 
    { 
    int bytesRead = SE_Process.StandardOutput.BaseStream.EndRead(result); // <-- Throws exceptions 

    if (0 != bytesRead) 
    { 
     // Write the received data in output textbox 
     ... 
    } 

    // Reset the callback 
    SE_Process.StandardOutput.BaseStream.BeginRead(SE_StdOutBuffer, 0, SE_BUFFERSIZE,  read_SE_StdOut, null); 
    } 
    catch (Exception exc) 
    { 
    // Do stuff 
    } 
} 

void SE_Process_Exited(object sender, EventArgs e) 
{ 

    // Keep track of whether or not the next script shall be started 
    bool continueSession = false; 

    switch (SE_Process.ExitCode) 
    { 
    case 0: // PASS 
    { 
     // Do stuff 
    } 

    ... 

    } 

    SE_Process.Dispose(); // TODO: Is it necessary to dispose of the process? 

    if (continueSession) 
    { 
    ts_incrementScriptListIndexer(); 

    if (scriptListIndexer == scriptList.Count) 
    { 
     // Last script has finished, reset the indexer and re-enable 
     // 'scriptListView' 
     ... 
    } 
    else 
    { 
     if (!startScript()) 
     { 
     // Do stuff 
     } 
    } 
    } 
    else 
    { 
    ts_resetScriptListIndexer(); 
    threadSafeEnableScriptListView(); 
    } 
} 

Điều gì xảy ra sau một quá trình SE thúc tôi nhận được một ngoại lệ kiểu InvalidOperationException nói rằng

StandardOut chưa được chuyển hướng hoặc quá trình này đã chưa bắt đầu.

từ cuộc gọi đến SE_Process.StandardOutput.BaseStream.EndRead(). Tôi không hiểu tại sao vì tôi đã đặt SE_Process.StartInfo.RedirectStandardOutput trước khi bắt đầu mọi quy trình mới. Nó xuất hiện với tôi như thể các dòng stdout của một quá trình thoát gọi hàm read_SE_StdOut() của tôi sau khi quá trình đã được xử lý, là có thể?

Cảm ơn bạn đã đọc!

+0

Bạn có thể quan tâm đến thư viện [MedallionShell] (https://github.com/madelson/MedallionShell), đơn giản hóa việc xử lý luồng io quy trình, đặc biệt là các hoạt động không đồng bộ – ChaseMedallion

Trả lời

2

Ngoại lệ bạn nhận được là bình thường. Một cuộc gọi BeginRead() không bao giờ có thể thành công: cuộc gọi cuối cùng, ngay sau khi quá trình chấm dứt. Bạn thường tránh gọi lại BeginRead() nếu bạn biết quá trình này đã hoàn tất, do đó bạn không bị ngoại lệ. Tuy nhiên, bạn hiếm khi biết. Chỉ cần bắt ngoại lệ. Hoặc sử dụng BeginOutputReadLine() thay vào đó, nó sẽ bắt nó cho bạn.

Tôi đoán bạn cũng chuyển hướng stderr và công cụ sử dụng công cụ này để xuất "X". Không có cách nào để giữ đầu ra trên cả hai chế độ đồng bộ hóa stderrstdout sau khi được đệm và chuyển hướng.

+0

Tôi hiểu, tôi sẽ xử lý ngoại lệ . Về trật tự bị xáo trộn của các ký tự; cũng là X: es được đưa ra trên stdout vì vậy tôi không nghĩ rằng giải thích lý do tại sao họ được trình bày ra khỏi trật tự. Tôi sẽ để cho câu hỏi này vẫn chưa được trả lời bởi vì vấn đề lớn nhất của tôi là hiển thị không chính xác của đầu ra (tôi nghĩ rằng nó có thể có liên quan đến ngoại lệ bằng cách nào đó nhưng có lẽ nó không phải là). Cảm ơn bạn vì câu trả lời! – jokki

+0

Vấn đề của tôi với việc hiển thị rối loạn các ký tự nhận được không còn xảy ra nữa, tôi phải tự sửa nó :) Tôi đã xóa phần câu hỏi trên và đặt câu hỏi thành "đã trả lời". Cảm ơn bạn một lần nữa! – jokki

Các vấn đề liên quan