dartdart-isolates

Why the exitPort hander `if` statement isn't called at the very end


In the below program the printTest method must be called at the end after all Isolates have finished but why is printTest method called before the isolates have finished. This condition checks if (--liveIsolates == 0) weather isolates have finished executing.

The Test class instance is used to check weather the instance is same inside of different isolates.

Source


import "dart:isolate";

Test test = Test();

void main(final List<String> args) async {
  final exitPort = RawReceivePort();
  const int numberOfIsolates = 1000;
  int liveIsolates = 0;

  exitPort.handler = (_) {
    print("Entering handler");

    final alpha = "abcdefghijklmnopqurstuvwxyz";
    print("$alpha $alpha $alpha $_");
    if (--liveIsolates == 0) {
      printTest();
      print("Closing the exitPort");
      exitPort.close();
    }

    print("Exiting handler");
  };

  liveIsolates = numberOfIsolates;

  for (int i = 0; i < numberOfIsolates; i++) { // creating multiple isolates
    final isolate1 =
        await Isolate.spawn(foo, exitPort.sendPort, onExit: exitPort.sendPort);
  }

  print("Exiting main");
}

void foo(final SendPort sendPort) {
  sendPort.send("Data to be send from foo");
  print("Entering foo sendPort id ${sendPort.hashCode}");
  test++;
  print("Exiting foo id test : ${test.hashCode}");
  print("Exiting foo id test : $test");
}

void printTest() { // should be called @ last by exitPort handler
  print("Value of test : $test");
}

class Test {
  int _data = 0;

  void set(int value) => _data = value;

  int get data => _data;

  @override
  String toString() {
    return _data.toString();
  }

  Test operator +(int _) { // overloading ++ operator
    _data++;
    return this;
  }
}

Why the below lines of statement is executed before all the isolates have finished? From the output of the above program we can see that this statement Closing the exitPort is displayed at in between instead of @ the very bottom.

if (--liveIsolates == 0) {
      printTest();
      print("Closing the exitPort");
      exitPort.close();
    }

Solution

  • As described in the comments, the issue with the current code is the following line:

    await Isolate.spawn(foo, exitPort.sendPort, onExit: exitPort.sendPort);
    

    Where exitPort.sendPort are being used twice, both for getting messages from the spawned Isolate and then also when the Isolate are stopping.

    By the current code, exitPort.sendPort gets sent two messages for each Isolate but exitPort.handler is designed to only receive one message for each spawned Isolate in its countdown logic.

    This means the following gets called way too early:

          exitPort.close();
    

    Since the main Isolate then no longer waits for any further communication with isolates, the Dart process are likely to be stopped early since Dart since Dart will not automatically wait for all spawned Isolate being executed. See the following for more detailed explanation about when Dart programs are stopped: https://stackoverflow.com/a/70670962/1953515