Output()
is to be called during waitForFinish()
waits. Something is wrong in the code implementing Command execution.
Most likely: the command executor (RootTools
?) runs the command on shell, gets a bunch of output lines, notifies the calling thread from waiting, and then calls output()
of command for each line it got as output. I think it should notify the command thread after output()
has been called on command object, for all output lines.
Still you can wrap the list modifying code and list iterating code in synchronized(<some common object>){}
.
Update:
So waitForFinish()
is not waiting? How do I prevent this race condition?
It does wait, but not for your code. Synchronized
keyword merely made sure that output()
of Command
object is not called at the same time when you are iterating the apps
collection. It does not schedule the two threads to run in a particular sequence.
IMHO, waitForFinish()
is not a good pattern, making calling thread waiting defeats the point of a separate executor. It better be formulated like an AsyncTask
or accept an event listener for each Command
object.
Just a rough example, this class:
public class RootTask extends AsyncTask<String,Void,List<String>> {
private boolean mSuccess;
public boolean isSuccess() {
return mSuccess;
}
@Override
protected List<String> doInBackground(String... strings) {
List<String> lines = new ArrayList<String>();
try {
Process p = Runtime.getRuntime().exec("su");
InputStream is = p.getInputStream();
OutputStream os = p.getOutputStream();
os.write((strings[0] + "\n").getBytes());
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = rd.readLine()) != null){
lines.add(line);
}
mSuccess = true;
os.write(("exit\n").getBytes());
p.destroy();
} catch (IOException e) {
mSuccess = false;
e.printStackTrace();
}
return lines;
}
}
can be used as:
RootTask listTask = new RootTask{
@Override
public void onPostExecute(List<String> result){
super.onPostExecute();
apps.addAll(result);
//-- or process the results strings--
}
};
listTask.execute("ls -a "+TIdir+"/*.properties");