/**
  * Cancels any construction threads. If background threads had been started for graph
  * construction, they will be stopped and the construction abandoned. Note that this will also
  * reset the number of additional threads to zero to prevent further threads from being started by
  * the existing ones before they terminate. If a thread is already blocked in a call to {@link
  * #getDependencyGraph} it will receive a {@link CancellationException} unless the graph
  * construction completes before the cancellation is noted by that or other background threads.
  * The cancellation is temporary, the additional threads can be reset afterwards for continued
  * background building or a subsequent call to getDependencyGraph can finish the work.
  *
  * @param mayInterruptIfRunning ignored
  * @return true if the build was cancelled
  */
 @Override
 public boolean cancel(final boolean mayInterruptIfRunning) {
   setMaxAdditionalThreads(0);
   synchronized (_activeJobs) {
     _cancelled = true;
     for (final Job job : _activeJobs) {
       job.cancel(true);
     }
     _activeJobs.clear();
   }
   return true;
 }
  private static <T> boolean invokeConcurrentlyForAll(
      @NotNull final List<? extends T> things,
      boolean failFastOnAcquireReadAction,
      @NotNull final Processor<T> thingProcessor)
      throws ProcessCanceledException {
    final Job<String> job = new JobImpl<String>(Job.DEFAULT_PRIORITY, failFastOnAcquireReadAction);

    final int chunkSize = Math.max(1, things.size() / JobSchedulerImpl.CORES_COUNT / 20);
    for (int i = 0; i < things.size(); i += chunkSize) {
      // this job chunk is i..i+chunkSize-1
      final int finalI = i;
      job.addTask(
          new Runnable() {
            public void run() {
              try {
                for (int k = finalI; k < finalI + chunkSize && k < things.size(); k++) {
                  T thing = things.get(k);
                  if (!thingProcessor.process(thing)) {
                    job.cancel();
                    break;
                  }
                }
              } catch (ProcessCanceledException e) {
                job.cancel();
                throw e;
              }
            }
          });
    }
    try {
      job.scheduleAndWaitForResults();
    } catch (RuntimeException e) {
      job.cancel();
      throw e;
    } catch (Throwable throwable) {
      job.cancel();
      throw new ProcessCanceledException(throwable);
    }
    return !job.isCanceled();
  }