প্রক্রিয়া.ওয়েটফোর () কখনই ফিরে আসে না


96
Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader = 
    new BufferedReader(new InputStreamReader(process.getInputStream()));
process.waitFor();

দয়া করে নোট করুন যে জাভা 8 এ ওভারলোডের জন্য অপেক্ষা রয়েছে যা আপনাকে নির্দিষ্ট সময়সীমা নির্দিষ্ট করে দেয়। এমন মামলা থেকে বিরত থাকার জন্য এটি আরও ভাল পছন্দ হতে পারে যেখানে অপেক্ষাও কখনও ফিরে আসে না।
ইকাসো

উত্তর:


146

waitFor()ফিরে আসে না এমন অনেকগুলি কারণ রয়েছে ।

তবে এটি কার্যকরভাবে কার্যকর হয় যে মৃত্যুদন্ড কার্যকর করা আদেশটি প্রস্থান করে না to

এর আবারও অনেক কারণ থাকতে পারে।

একটি সাধারণ কারণ প্রক্রিয়াটি কিছু আউটপুট উত্পাদন করে এবং আপনি উপযুক্ত স্ট্রিমগুলি থেকে পড়েন না। এর অর্থ হল বাফারটি পূর্ণ হওয়ার সাথে সাথে প্রক্রিয়াটি অবরুদ্ধ হয়ে যায় এবং আপনার প্রক্রিয়াটি পড়া চালিয়ে যাওয়ার জন্য অপেক্ষা করে। পরিবর্তে আপনার প্রক্রিয়াটি অন্য প্রক্রিয়াটি শেষ হওয়ার জন্য অপেক্ষা করে (যা এটি হবে না কারণ এটি আপনার প্রক্রিয়ার জন্য অপেক্ষা করে, ...)। এটি একটি শাস্ত্রীয় অচলাবস্থার পরিস্থিতি।

এটি যাতে অবরুদ্ধ হয় না তা নিশ্চিত করতে আপনার ক্রমাগত প্রসেস ইনপুট স্ট্রিম থেকে পড়তে হবে।

একটি দুর্দান্ত নিবন্ধ রয়েছে যা এর সমস্ত দোষত্রুটিগুলি ব্যাখ্যা Runtime.exec()করে এবং তাদের চারপাশের উপায়গুলি দেখায় যেগুলি "যখন রানটাইম.এক্সেক () হবে না" নামে পরিচিত (হ্যাঁ, নিবন্ধটি 2000 সালের, তবে সামগ্রীতে এখনও প্রযোজ্য!)


8
এই উত্তরটি সঠিক তবে সমস্যা সমাধানের জন্য এটি একটি কোডের নমুনা মিস করে। কেন waitFor()ফিরে আসে না তা জানতে দরকারী কোডের জন্য পিটার লরির উত্তরটি দেখুন ।
ভুলে গেছেন

84

দেখা যাচ্ছে আপনি শেষ হওয়ার অপেক্ষার আগে আউটপুটটি পড়ছেন না। আউটপুট বাফারটি পূরণ না করলেই এটি সূক্ষ্ম। যদি এটি হয়ে থাকে তবে আপনি আউটপুট, ক্যাপ -২২ পড়া না হওয়া পর্যন্ত এটি অপেক্ষা করবে।

সম্ভবত আপনার কিছু ভুল রয়েছে যা আপনি পড়ছেন না। এটি অ্যাপ্লিকেশনটি থামবে এবং অপেক্ষা করবে চিরকাল অপেক্ষা করার জন্য। এর চারপাশের একটি সহজ উপায় হ'ল নিয়মিত আউটপুটে ত্রুটিগুলি পুনরায় নির্দেশ করা।

ProcessBuilder pb = new ProcessBuilder("tasklist");
pb.redirectErrorStream(true);
Process process = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null)
    System.out.println("tasklist: " + line);
process.waitFor();

4
তথ্যের জন্য: প্রসেসবিল্ডার একজন প্রকৃত নির্মাতা, আপনি সরাসরি প্রসেসবিল্ডার পিবি = নতুন প্রসেসবিল্ডার ("টাস্কলিস্ট") লিখতে পারেন red redirectErrorStream (সত্য);
জিন-ফ্রান্সোয়েস সাভার্ড

4
আমি বরং ব্যবহার করবpb.redirectError(new File("/dev/null"));
টুচকা

@ টুচকা কেবল তথ্যের জন্য, redirectErrorকেবল জাভা 1.7 থেকে পাওয়া যাবে
Zেকা কোজলভ

4
আমার বিশ্বাসযোগ্য গ্রহণযোগ্য উত্তর হওয়া উচিত, আমি আমার কোডটি এর সাথে প্রতিস্থাপন করেছি এবং এটি অবিলম্বে কাজ করেছে।
গারবেন রাম্পার্ট

43

জাভা ডক থেকেও:

java.lang

ক্লাস প্রক্রিয়া

কিছু স্থানীয় প্ল্যাটফর্ম কেবলমাত্র স্ট্যান্ডার্ড ইনপুট এবং আউটপুট স্ট্রিমগুলির জন্য সীমিত বাফার আকার সরবরাহ করে, তত্ক্ষণাত্ ইনপুট স্ট্রিমটি লিখতে বা সাবপ্রসেসের আউটপুট স্ট্রিমটি পড়তে ব্যর্থতা সাবপ্রসেসকে অবরুদ্ধ করতে পারে এবং এমনকি অচলাবস্থার কারণ হতে পারে।

প্রক্রিয়া থেকে ইনপুট স্ট্রিমের বাফার সাফ করতে ব্যর্থ (যা সাবপ্রসেসের আউটপুট স্ট্রিমের পাইপগুলি) সাবপ্রসেস ব্লক করতে পারে।

এটা চেষ্টা কর:

Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((reader.readLine()) != null) {}
process.waitFor();

17
দুটি সতর্কতা: (1) প্রসেসবিল্ডার + রিডাইরেক্ট এরিরস্ট্রিম (সত্য) ব্যবহার করুন, তবে আপনি নিরাপদ are অন্যটি, (২) আপনার প্রসেস.জেটআরপট স্ট্রিম () থেকে পড়ার জন্য একটি থ্রেড এবং অন্যটি প্রসেস.জেটআররস্ট্রিম () থেকে পড়তে হবে। এটি আবিষ্কার করার জন্য (!) প্রায় চার ঘন্টা ব্যয় করেছে, "দ্য হার্ড ওয়ে"।
কেভিনার্পে

4
আপনি DefaultExecutor executor = new DefaultExecutor(); PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(stdoutOS, stderrOS); executor.setStreamHandler(pumpStreamHandler); executor.execute(cmdLine);স্টাডিআউট এবং স্ট্ডার স্ট্রিমগুলি একসাথে গ্রাস করতে অ্যাপাচি কমন্স এক্সিকিউটিভিলিটি ব্যবহার করতে পারেন: যেখানে স্টাটোস এবং স্টেডারসগুলি BufferedOutputStreamউপযুক্ত ফাইলগুলিতে লিখতে আমি তৈরি করেছি।
ম্যাথু ওয়াইজ

আমার ক্ষেত্রে আমি স্প্রিং থেকে একটি ব্যাচের ফাইলটি কল করছিলাম যা অভ্যন্তরীণভাবে একটি সম্পাদক খোলায়। কোড প্রয়োগ করার পরেও আমার কোডটি ঝুলছিল process.close()। কিন্তু যখন আমি উপরে প্রস্তাবিত ইনপুট স্ট্রিমটি খুলি এবং অবিলম্বে বন্ধ করি - সমস্যাটি চলে যায়। সুতরাং আমার ক্ষেত্রে বসন্ত স্ট্রিমের কাছাকাছি সিগন্যালের জন্য অপেক্ষা করছিল। যদিও আমি জাভা 8 অটো ক্লোজেবল ব্যবহার করছি।
শাইলু

11

আমি পূর্বের উত্তরে কিছু যুক্ত করতে চাই তবে যেহেতু আমার কাছে মন্তব্য করার মতামত নেই, আমি কেবল একটি উত্তর যুক্ত করব। এটি জাভাতে প্রোগ্রামিং করা অ্যান্ড্রয়েড ব্যবহারকারীদের দিকে পরিচালিত।

রোলিংবয়ের পোস্ট অনুসারে, এই কোডটি প্রায় আমার জন্য কাজ করেছিল:

Process process = Runtime.getRuntime().exec("tasklist");
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((reader.readLine()) != null) {}
process.waitFor();

আমার ক্ষেত্রে, ওয়েটারফোর () প্রকাশ হচ্ছে না কারণ আমি কোনও রিটার্ন ছাড়াই একটি বিবৃতি কার্যকর করছিলাম ("আইপি অ্যাড্ডার ফ্লাশ এথ0")। এটির সমাধানের একটি সহজ উপায় হ'ল আপনার বিবৃতিতে সর্বদা কিছু ফিরিয়ে দেওয়া নিশ্চিত করা। আমার জন্য, এর অর্থ নিম্নলিখিতগুলি সম্পাদন করা ছিল: "আইপি অ্যাড্ডার ফ্লাশ এথ0 && ইকো সম্পন্ন হয়েছে"। আপনি সারা দিন বাফারটি পড়তে পারেন, তবে যদি কখনও কিছুই ফেরত না পাওয়া যায় তবে আপনার থ্রেড কখনও অপেক্ষা করবে না।

আশা করি যে কাউকে সাহায্য করবে!


4
আপনার কাছে যখন মন্তব্য করার মতামত নেই, তখন এটিকে ঘিরে কাজ করবেন না এবং যেভাবেই মন্তব্য করবেন না । এটি নিজে থেকে একটি উত্তর তৈরি করুন এবং এটি থেকে প্রতিনিধি পান!
মনিকার লসুইট

আমি মনে করি না এটি যদি এটির process.waitFor()স্তব্ধ হয় তবে reader.readLine()এটি যদি আপনার কোনও আউটপুট না থাকে তবে এটি স্তব্ধ হয়। আমি waitFor(long,TimeUnit)যদি কিছু ভুল হয়ে যায় এবং টু টাইমআউটটি ব্যবহার করার চেষ্টা করেছিলাম যে এটি হ্যাং হ্যাড। যা সময় নির্ধারিত সংস্করণে পড়ার জন্য অন্য থ্রেডের প্রয়োজন ...
ওসুন্ডব্ল্যাড

5

বিভিন্ন সম্ভাবনা রয়েছে:

  1. আপনি প্রক্রিয়াটির সমস্ত আউটপুট গ্রাস করেন নি stdout
  2. আপনি প্রক্রিয়াটির সমস্ত আউটপুট গ্রাস করেন নি stderr
  3. প্রক্রিয়াটি আপনার কাছ থেকে ইনপুটটির জন্য অপেক্ষা করছে এবং আপনি এটি সরবরাহ করেন নি, বা আপনি প্রক্রিয়াটি বন্ধ করেন নিstdin
  4. প্রক্রিয়াটি একটি হার্ড লুপে ঘুরছে।

5

অন্যরা যেমন উল্লেখ করেছে আপনাকে স্ট্যাডার এবং স্টাডাউট গ্রহণ করতে হবে

অন্যান্য উত্তরগুলির সাথে তুলনা করুন, জাভা 1.7 যেহেতু এটি আরও সহজ। স্ট্যাডার এবং স্টাডাউট পড়ার জন্য আপনাকে আর থ্রেড তৈরি করতে হবে না

শুধু ব্যবহার ProcessBuilderও পদ্ধতি ব্যবহার redirectOutputসঙ্গে পারেন একযোগে redirectErrorবা redirectErrorStream

String directory = "/working/dir";
File out = new File(...); // File to write stdout to
File err = new File(...); // File to write stderr to
ProcessBuilder builder = new ProcessBuilder();
builder.directory(new File(directory));
builder.command(command);
builder.redirectOutput(out); // Redirect stdout to file
if(out == err) { 
  builder.redirectErrorStream(true); // Combine stderr into stdout
} else { 
  builder.redirectError(err); // Redirect stderr to file
}
Process process = builder.start();

2

একই কারণে আপনি inheritIO()বাহ্যিক অ্যাপ্লিকেশন কনসোলের সাথে জাভা কনসোলটি মানচিত্র করতেও ব্যবহার করতে পারেন:

ProcessBuilder pb = new ProcessBuilder(appPath, arguments);

pb.directory(new File(appFile.getParent()));
pb.inheritIO();

Process process = pb.start();
int success = process.waitFor();

2

আপনার একই সময়ে আউটপুট এবং ত্রুটি গ্রাস করার চেষ্টা করা উচিত

    private void runCMD(String CMD) throws IOException, InterruptedException {
    System.out.println("Standard output: " + CMD);
    Process process = Runtime.getRuntime().exec(CMD);

    // Get input streams
    BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
    BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
    String line = "";
    String newLineCharacter = System.getProperty("line.separator");

    boolean isOutReady = false;
    boolean isErrorReady = false;
    boolean isProcessAlive = false;

    boolean isErrorOut = true;
    boolean isErrorError = true;


    System.out.println("Read command ");
    while (process.isAlive()) {
        //Read the stdOut

        do {
            isOutReady = stdInput.ready();
            //System.out.println("OUT READY " + isOutReady);
            isErrorOut = true;
            isErrorError = true;

            if (isOutReady) {
                line = stdInput.readLine();
                isErrorOut = false;
                System.out.println("=====================================================================================" + line + newLineCharacter);
            }
            isErrorReady = stdError.ready();
            //System.out.println("ERROR READY " + isErrorReady);
            if (isErrorReady) {
                line = stdError.readLine();
                isErrorError = false;
                System.out.println("ERROR::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::" + line + newLineCharacter);

            }
            isProcessAlive = process.isAlive();
            //System.out.println("Process Alive " + isProcessAlive);
            if (!isProcessAlive) {
                System.out.println(":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Process DIE " + line + newLineCharacter);
                line = null;
                isErrorError = false;
                process.waitFor(1000, TimeUnit.MILLISECONDS);
            }

        } while (line != null);

        //Nothing else to read, lets pause for a bit before trying again
        System.out.println("PROCESS WAIT FOR");
        process.waitFor(100, TimeUnit.MILLISECONDS);
    }
    System.out.println("Command finished");
}

1

আমি মনে করি আমি একটি অনুরূপ সমস্যা পর্যবেক্ষণ করেছি: কিছু প্রক্রিয়া শুরু হয়েছে, মনে হয়েছে সফলভাবে চলছে তবে কখনও শেষ হয়নি। টাস্ক ম্যানেজারে আমি প্রক্রিয়াটি মেরে ফেলা ব্যতীত অপেক্ষার জন্য অপেক্ষা ফাংশনটি চিরকাল অপেক্ষা করছিল।
যাইহোক, কমান্ড লাইনের দৈর্ঘ্য 127 অক্ষর বা তার চেয়ে কম ক্ষেত্রে সমস্ত কিছু ভাল কাজ করেছিল। যদি দীর্ঘ ফাইলের নামগুলি অনিবার্য হয় তবে আপনি পরিবেশগত ভেরিয়েবলগুলি ব্যবহার করতে চাইতে পারেন, যা আপনাকে কমান্ড লাইনের স্ট্রিংটি ছোট রাখার অনুমতি দিতে পারে। আপনি এমন একটি ব্যাচ ফাইল তৈরি করতে পারেন (ফাইল রাইটার ব্যবহার করে) আপনি যে প্রোগ্রামটি চালাতে চান তার কল করার আগে আপনি আপনার পরিবেশগত পরিবর্তনশীল সেট করেছেন। এই জাতীয় ব্যাচের বিষয়বস্তু দেখতে পাওয়া যেতে পারে:

    set INPUTFILE="C:\Directory 0\Subdirectory 1\AnyFileName"
    set OUTPUTFILE="C:\Directory 2\Subdirectory 3\AnotherFileName"
    set MYPROG="C:\Directory 4\Subdirectory 5\ExecutableFileName.exe"
    %MYPROG% %INPUTFILE% %OUTPUTFILE%

শেষ সময়টি রানটাইম ব্যবহার করে এই ব্যাচ ফাইলটি চালাচ্ছে।


1

এখানে একটি পদ্ধতি যা আমার পক্ষে কাজ করে। দ্রষ্টব্য: এই পদ্ধতির মধ্যে এমন কিছু কোড রয়েছে যা আপনার ক্ষেত্রে প্রযোজ্য নয়, তাই চেষ্টা করুন এবং এটিকে এড়িয়ে যান। উদাহরণস্বরূপ "লগস্ট্যান্ডার্ডআউট (...), গিট-ব্যাশ, ইত্যাদি"।

private String exeShellCommand(String doCommand, String inDir, boolean ignoreErrors) {
logStandardOut("> %s", doCommand);

ProcessBuilder builder = new ProcessBuilder();
StringBuilder stdOut = new StringBuilder();
StringBuilder stdErr = new StringBuilder();

boolean isWindows = System.getProperty("os.name").toLowerCase().startsWith("windows");
if (isWindows) {
  String gitBashPathForWindows = "C:\\Program Files\\Git\\bin\\bash";
  builder.command(gitBashPathForWindows, "-c", doCommand);
} else {
  builder.command("bash", "-c", doCommand);
}

//Do we need to change dirs?
if (inDir != null) {
  builder.directory(new File(inDir));
}

//Execute it
Process process = null;
BufferedReader brStdOut;
BufferedReader brStdErr;
try {
  //Start the command line process
  process = builder.start();

  //This hangs on a large file
  // /programming/5483830/process-waitfor-never-returns
  //exitCode = process.waitFor();

  //This will have both StdIn and StdErr
  brStdOut = new BufferedReader(new InputStreamReader(process.getInputStream()));
  brStdErr = new BufferedReader(new InputStreamReader(process.getErrorStream()));

  //Get the process output
  String line = null;
  String newLineCharacter = System.getProperty("line.separator");

  while (process.isAlive()) {
    //Read the stdOut
    while ((line = brStdOut.readLine()) != null) {
      stdOut.append(line + newLineCharacter);
    }

    //Read the stdErr
    while ((line = brStdErr.readLine()) != null) {
      stdErr.append(line + newLineCharacter);
    }

    //Nothing else to read, lets pause for a bit before trying again
    process.waitFor(100, TimeUnit.MILLISECONDS);
  }

  //Read anything left, after the process exited
  while ((line = brStdOut.readLine()) != null) {
    stdOut.append(line + newLineCharacter);
  }

  //Read anything left, after the process exited
  while ((line = brStdErr.readLine()) != null) {
    stdErr.append(line + newLineCharacter);
  }

  //cleanup
  if (brStdOut != null) {
    brStdOut.close();
  }

  if (brStdErr != null) {
    brStdOut.close();
  }

  //Log non-zero exit values
  if (!ignoreErrors && process.exitValue() != 0) {
    String exMsg = String.format("%s%nprocess.exitValue=%s", stdErr, process.exitValue());
    throw new ExecuteCommandException(exMsg);
  }

} catch (ExecuteCommandException e) {
  throw e;
} catch (Exception e) {
  throw new ExecuteCommandException(stdErr.toString(), e);
} finally {
  //Log the results
  logStandardOut(stdOut.toString());
  logStandardError(stdErr.toString());
}

return stdOut.toString();

}


0

একটি সময়সীমার সাথে অপেক্ষা করা এড়িয়ে যাওয়ার সাথে মিলিত স্ট্রিমের অ্যাসিঙ্ক্রোনাস রিডিং সমস্যার সমাধান করবে।

আপনি এখানে এটি ব্যাখ্যা করে একটি পৃষ্ঠা পেতে পারেন

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.