
groovyx.gpars.dataflow.impl.SelectBase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gpars Show documentation
Show all versions of gpars Show documentation
The Groovy and Java high-level concurrency library offering actors, dataflow, CSP, agents, parallel collections, fork/join and more
// GPars - Groovy Parallel Systems
//
// Copyright © 2008-11 The original author or authors
//
// 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 groovyx.gpars.dataflow.impl;
import groovyx.gpars.dataflow.Dataflow;
import groovyx.gpars.dataflow.DataflowReadChannel;
import groovyx.gpars.dataflow.DataflowVariable;
import groovyx.gpars.dataflow.expression.DataflowExpression;
import groovyx.gpars.group.PGroup;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Random;
/**
* The implementation of the core for all selects.
*
* @author Vaclav Pech
* Date: 29th Sep 2010
*/
@SuppressWarnings({"rawtypes", "RawUseOfParameterizedType"})
public final class SelectBase {
private final List> channels;
private final int numberOfChannels;
/**
* Since DataflowVariables should be only read once, they need to be disabled after selecting their value
* The array stores a boolean flag for each index, indicating, whether the channel/variable has been disabled
*/
private final boolean[] disabledDFVs;
/**
* Unsatisfied requests for value, each holding a list of guards and a routine to invoke once a value is available
*/
private final Collection> pendingRequests = new ArrayList>();
@SuppressWarnings({"UnsecureRandomNumberGeneration"})
private final Random position = new Random();
/**
* Stores the input channel and registers for the wheneverBound() event on each
*
* @param pGroup The group, the thread pool of which should be used for notification message handlers
* @param channels All the input channels to select on
*/
public SelectBase(final PGroup pGroup, final List> channels) {
this.channels = Collections.unmodifiableList(channels);
numberOfChannels = channels.size();
disabledDFVs = new boolean[numberOfChannels];
Arrays.fill(disabledDFVs, false);
for (int i = 0; i < numberOfChannels; i++) {
final DataflowReadChannel extends T> channel = channels.get(i);
final PGroup originalGroup = Dataflow.retrieveCurrentDFPGroup();
try {
Dataflow.activeParallelGroup.set(pGroup);
//noinspection ThisEscapedInObjectConstruction
channel.wheneverBound(new SelectCallback(this, i, channel));
} finally {
Dataflow.activeParallelGroup.set(originalGroup);
}
}
}
/**
* Invoked by the SelectCallback instances, potentially concurrently to inform about new values being available for read from channels.
*
* @param index The index of the ready channel
* @param channel The channel itself
* @throws InterruptedException If the thread is interrupted during value retrieval from the channel
*/
@SuppressWarnings({"MethodOnlyUsedFromInnerClass"})
void boundNotification(final int index, final DataflowReadChannel extends T> channel) throws InterruptedException {
synchronized (channels) {
for (final SelectRequest selectRequest : pendingRequests) {
if (selectRequest.matchesMask(index) && !disabledDFVs[index]) {
final DataflowExpression extends T> value = channel.poll();
if (value != null) {
pendingRequests.remove(selectRequest);
disableDFV(index, channel);
selectRequest.valueFound(index, value.getVal());
return;
}
}
}
}
}
/**
* Invoked whenever the Select is asked for the next value. Depending on the supplied startIndex value it scans
* all input channels and reads the first one found, which currently has a value available for read.
* If no input channel is ready, the supplied SelectRequest instance is registered to be notified by the wheneverBound() channel listeners.
*
* @param startIndex The index of the channel to check first for available messages, -1 if start at a random position. Continue scanning by increasing the index, once the size is reached start from 0.
* @param selectRequest The request that holds the guards and expects a notification once a value is selected
* @throws InterruptedException If the thread gets interrupted while reading messages from the channels
*/
public void doSelect(final int startIndex, final SelectRequest selectRequest) throws InterruptedException {
final int startPosition = startIndex == -1 ? position.nextInt(numberOfChannels) : startIndex;
synchronized (channels) {
for (int i = 0; i < numberOfChannels; i++) {
final int currentPosition = (startPosition + i) % numberOfChannels;
if (selectRequest.matchesMask(currentPosition) && !disabledDFVs[currentPosition]) {
final DataflowReadChannel extends T> channel = channels.get(currentPosition);
final DataflowExpression extends T> value = channel.poll();
if (value != null) {
disableDFV(currentPosition, channel);
selectRequest.valueFound(currentPosition, value.getVal());
return;
}
}
}
pendingRequests.add(selectRequest);
}
}
/**
* Sets the flag in the disabledDFVs array, if the channel is a DFV
*
* @param currentPosition The position to mark
* @param channel The channel being considered
*/
private void disableDFV(final int currentPosition, final DataflowReadChannel extends T> channel) {
if (channel instanceof DataflowVariable) disabledDFVs[currentPosition] = true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy