/******************************************************************************* * Copyright 2013 Analog Devices, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ package com.analog.lyric.dimple.solvers.core.multithreading.singlequeuealgorithm; import java.util.concurrent.Callable; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.jdt.annotation.Nullable; import com.analog.lyric.dimple.schedulers.dependencyGraph.StaticDependencyGraphNode; import com.analog.lyric.dimple.solvers.interfaces.ISolverFactorGraph; /* * Object that retrieves data from the work queue until there is nothing left. * * Package protected */ class SingleQueueWorker implements Callable<Object> { private final ISolverFactorGraph _solverGraph; private final LinkedBlockingQueue<StaticDependencyGraphNode> _workQueue; private final AtomicInteger _nodesDone; SingleQueueWorker( ISolverFactorGraph solverGraph, LinkedBlockingQueue<StaticDependencyGraphNode> workQueue, int numNodes, AtomicInteger nodesDone) { _solverGraph = solverGraph; _workQueue = workQueue; _nodesDone = nodesDone; } @Override public @Nullable Object call() throws Exception { //Keep going until there is nothing left. while(true) { StaticDependencyGraphNode entry = _workQueue.take(); // Pull the next entry from the work queue (blocking if there are none) //If we find sentinel, there's nothing left to do. Put the sentinel back for the next thread. if (entry.isSentinel()) { _workQueue.add(entry); break; } //run the update. _solverGraph.runScheduleEntry(entry.getScheduleEntry()); //Decrement the number of ndoes that are done. int nodesLeft = _nodesDone.decrementAndGet(); //If we're done, add sentinel and quit. if (nodesLeft == 0) { _workQueue.add(StaticDependencyGraphNode.createSentinel()); break; } //For every single dependent, we have to decrement dependencies and, //if those reach 0, add the dependency to the queue. for (int i = 0; i < entry.getNumDependents(); i++) { StaticDependencyGraphNode dependent = entry.getDependent(i); //We have to synchronize the decrement of number of dependencies. int numDepsLeft = 0; synchronized (dependent) { //Decrement numDepsLeft = dependent.getNumDependenciesLeft(); numDepsLeft--; dependent.setNumDependenciesLeft(numDepsLeft); } //If there are 0 dependencies left, this was the last guy to touch it so //we can add a guy to the queue and reset the number of dependencies left. if (numDepsLeft == 0) { _workQueue.add(dependent); dependent.setNumDependenciesLeft(dependent.getNumDependencies()); } } } return null; } }