package org.port;
/*
The number of ports in the array is set when creating the object.
The following semaphores are used:
-sem_send_mutex- Guarantees mutual exclusion for threads calling the send() operation.
-mutex- Used for mutual exclusion when accessing the variables shared between the send() and receive() operations.
-sem_receive-used to block the receive operation if no thread is ready to send a message on any of the ports in pa. Its value is initially 0.
Contains two public methods and 1 private method.
public methods
- public <T> void send(T message, int p) throws PortNotAvailable - Sends a message to port at index p and it throws PortNotAvailable exception if index p
is invalid.
Otherwise a counter of the threads ready to send a message on the specified port is incremented and sem_receive is signalled hence the receive operation can continue.
- public <T> T receive():- Reads a message from any of the ports in pa that have messages.
When called, it blocks on sem_receive waiting for any thread to call the send operation.
This operation blocks if no thread has called the send operation.ie. If there is no message in any port.
If a message is available from multiple ports, one of the ports is selected at random by the method selectPort() and a message is read from it.
private method(s)
-private int selectPort(): -Selects an index at random from the non empty ports in pa( ports array)
*/
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.Semaphore;
import org.fairsem.fairSemaphore;
public class Ports<T> {
private ArrayList<Port> pa;
private fairSemaphore sem_mutex_send;
private fairSemaphore sem_receive;
private fairSemaphore mutex;
private int num_ports;
private ArrayList<Integer> num_messages;
public Ports(int size) {
pa = new ArrayList<Port>(size);
num_messages = new ArrayList<>(size);
num_ports = size;
sem_mutex_send = new fairSemaphore(1);
sem_receive = new fairSemaphore(0);
mutex = new fairSemaphore(1);
for (int i = 0; i < num_ports; i++) {
pa.add(new Port<T>());
num_messages.add(0);
}
}
public <T> void send(T message, int p) throws PortNotAvailable {
sem_mutex_send.P();
if (p >= num_ports) {
sem_mutex_send.V();
throw new PortNotAvailable();
}
mutex.P();
num_messages.set(p, num_messages.get(p)+1);
mutex.V();
sem_receive.V();
Port port = (Port) pa.get(p);
port.send(message);
sem_mutex_send.V();
}
public <T> T receive() {
int pi=0;
sem_receive.P();
mutex.P();
pi=selectPort();
Port port = (Port) pa.get(pi);
T message = (T) port.receive();
num_messages.set(pi,num_messages.get(pi)-1);
mutex.V();
return message;
}
private int selectPort() {
Random rand=new Random();
ArrayList<Integer> full=new ArrayList<Integer>();
for(int i=0;i<num_messages.size();i++)
{
if(num_messages.get(i)!=0)
full.add((Integer)i);
}
int index=rand.nextInt(full.size());
return full.get(index);
}
}