7

Tôi sử dụng ProcessBuilder để chạy quy trình. Tôi xử lý các luồng đầu vào/đầu ra bằng cách gửi các runnables tương ứng xử lý chúng trong một nhóm luồng (Executors.newCachedThreadPool()).
Tôi nhận được kết quả nhưng hiện tại tôi không nhận được gì cả.
Ví dụ: nếu tôi làm: cmd \C dir cho người xây dựng quy trình, tôi nhận được kết quả của dir trở lại nhưng đôi khi tôi không nhận được bất kỳ thứ gì (mặc dù kết quả có vẻ như trở lại từ runnable xử lý process.getInputStream).
Tôi làm cách nào để gỡ lỗi này? Nó xuất hiện liên tục. Với cùng mã tôi không có bất kỳ vấn đề gì khi tôi đã làm new Thread(runnable).start(). Nó bắt đầu xảy ra sau khi tôi chuyển sang một hồ bơi thread.Vấn đề đồng thời giữa chờ đợi quy trình và đọc luồng?

Cập nhật:
Tôi nghĩ rằng tôi tìm thấy một cái gì đó:
tôi làm như sau trong Runnable:

try { 
    while ((line = br.readLine()) != null) { 
      pw.println(line); 
       sb.append(line); 
    } 
    System.out.println("Finished reading "+sb.length()); 
} catch (IOException e) {    
    e.printStackTrace(); 
} 
finally{ 
    pw.flush();  
    try{ 
    isr.close(); 
    }catch(Exception e){} 
} 

Trong những trường hợp đó không làm việc nó in Finished reading 521. Nhưng tôi cố gắng lấy kết quả qua số pw và không phải là sb.
pw là PrintWriter pw = PrintWriter (OutputStream); `mà tôi vượt qua trong Runnable

Cập nhật 2:
Dường như: status = process.waitFor(); lợi nhuận trước trước các Runnable rằng xử lý kết thúc inputstream. Làm thế nào điều này có thể xảy ra?
Tôi đọc trong javadoc:
the calling thread will be blocked until the subprocess exits. Vậy điều đó có nghĩa là tôi có thể trả về trước khi tiêu thụ luồng I/O không?

Cập nhật 3:
Có vẻ là cùng một vấn đề ở đây trong Ruby
Tức là có một số điều kiện chủng tộc giữa quá trình kết thúc và tiêu thụ đầu ra

+0

Nếu quá trình gọi một quy trình khác, quy trình đầu tiên có thể trả về hành vi sớm - bình thường. – Sebastian

+0

Điều này không phải về việc trở về sớm.Đó là về việc trả lại * trước khi * các luồng đầu ra đã được tiêu thụ – Jim

Trả lời

1

Có. stdio giữa các quá trình được đệm (thường là bộ đệm 4KB). Quy trình A ghi vào bộ đệm và tồn tại. Quy trình B có hai luồng; một trong những chờ đợi cho đến cuối của A và người kia đọc đầu ra từ A. Không có cách nào để chắc chắn mà thread thực hiện đầu tiên.

Vì vậy, có thể (ngay cả khi có nhiều đầu ra) mà process.waitFor(); trả về trước khi tất cả đầu ra đã được đọc.

Lưu ý rằng xả nước không giúp được ở đây vì nó chỉ đảm bảo rằng A có được viết mọi thứ. Không có cách nào để "buộc" B đọc dữ liệu theo cách tương tự.

Vì vậy, bạn nên nhớ trạng thái thoát và xem xét quy trình là "đã chấm dứt hoàn toàn" chỉ khi bạn đọc EOF từ luồng đầu vào.

EDIT Một giải pháp sẽ được di chuyển waitFor() vào người ăn tạp stream và chuyển đổi người ăn tạp thành một Callable mà sau đó bạn có thể gửi cho người thi hành và sử dụng Future API (example) để có được kết quả (s).

+0

Vì vậy, làm thế nào tôi nên sửa đổi mã của tôi để xử lý? Tôi chỉ cần 'waitFor' bây giờ và mã trong trình đọc luồng của tôi được đăng – Jim

+1

Gọi 'waitFor' và sau đó' join() 'trên luồng chứa trình xử lý luồng. Hoặc có trình xử lý dòng gọi 'waitFor()' bên ngoài vòng lặp 'while()' để có cả hai ở cùng một vị trí. –

+0

1) Trình xử lý luồng được gửi đến một trình thực thi. Làm thế nào tôi có thể 'join'? 2) Làm thế nào để trình xử lý luồng có thể gọi' waitFor'? Kết quả được cho là được chuyển đến luồng đang chờ quá trình hoàn thành – Jim