/ / Najpierw najkrótszy pozostały czas: Java Multithreading - Java, wielowątkowość, procesor, planowanie, symulacja

Najkrótszy pozostały czas: Java Multithreading - Java, wielowątkowość, procesor, planowanie, symulacja

Próbuję symulować algorytmy planowania procesoraw java i używam wielowątkowości. Z powodzeniem wdrożyłem FCFS (First Come First Serve) i SJF (Shortest Job First). Problem jednak pojawia się, gdy zaczynam myśleć o SRTF (Shortest Remaining First First), który jest formą zapobiegawczą SJF. Korzystam z następującego modelu:

  • Wątek dla procesora, który ma CLOCK zmienna, która co tyka (prosty przyrost zegara) co 100ms. mam boolean isAvailable; flaga dla procesów, aby sprawdzić, czy procesor jest dostępny przed rozpoczęciem wykonywania.
  • Wątek dla Long Term Scheduler (LTS), który wypycha proces z listy procesów do Gotowej kolejki.
  • Wątek dla programu krótkoterminowego (STS), który pobiera proces z ReadyQueue i przypisuje go do procesora.
  • Po usunięciu procesu przez STS z ReadyQueue do wykonania, proces sprawdza, czy isAvailable flaga procesora. Gdyby true, ustawia flagę na fałsz i rozpoczyna jej wykonanie (dla którego właśnie robię wątek do spania (100 * burstTime) ms ponieważ jest to tylko symulacja). W przeciwnym razie proces będzie po prostu zajęty czekaniem: while(CPU.isAvailable != true);.

Mam listę procesów wraz z nimiczasy przybycia i wybuchu przed ręką. Jest ok, dopóki nie będę symulować nieprzewidywalnego planowania (FCFS i SJF). Ale kiedy próbuję SRTF, nie jestem w stanie znaleźć sposobu, aby zapobiec aktualnie działającemu wątkowi procesu.

W przypadku SRTF znam drogę do wyboru następnego procesu z ReadyQueue. Mogę spróbować ustawić isAvailable flaga do false raz wybieram proces z kolejki, ale potemskąd mam wiedzieć, który wątek był pierwotnie wykonywany? A ponieważ nie używam dużo wątków synchronizacji czarno-białych, będę mieć wiele procesów korzystających z CPU wątek. Trochę się popsuło. Proszę pomóż. Dzięki!

To jest kod procesu:

enum State {ARRIVED, WAITING, READY, RUNNING, EXECUTED}
public class Process implements Runnable
{
int pid;
int arrTime;
int burstTime;
int priority;
long startTime;
long endTime;
State procState = null;

Process(int pid, int arrTime, int burstTime, int priority)
{
this.pid = pid;
this.arrTime = arrTime;
this.burstTime = burstTime;
this.priority = priority;
this.procState = State.ARRIVED;
this.startTime = 0;


this.endTime = 0;    /* I also considered adding a timeElapsedUnderExecution
attribute to the process. So I can check after every cycle if the CPU is still available
and keep incrementing the time elapsed. Once the timeElapsed becomes same as burstTime, i
stop the process. Or if after a cycle, the CPU is not available, i know from where to
resume my Process. Is this the way to go ? */

}

boolean isReady()
{
if((this.arrTime <= CPU.CLOCK) && (this.procState == State.ARRIVED))
return true;
else return false;
}

@Override
public void run() {
// TODO Auto-generated method stub
if(this.procState == State.READY)
this.procState = State.WAITING;

while(!CPU.isAvailable());

try
{
this.procState = State.RUNNING;
System.out.println("Process " + pid + " executing...");
this.startTime = CPU.CLOCK;
System.out.println("Process " + this.pid + ": Begins at " + this.startTime);
Thread.sleep(this.burstTime * 100);
this.endTime = CPU.CLOCK;
System.out.println("Process " + this.pid + ": Ends at " + this.endTime);
this.procState = State.EXECUTED;

}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
System.out.println("Interrupted: " + pid);
e.printStackTrace();
}
}
}

Kod procesora:

    import java.util.LinkedList;
import java.util.Queue;

public class CPU implements Runnable

{
static Long CLOCK = new Long(0);
static LinkedList<Process> ReadyQ = new LinkedList<Process>();
private static boolean isAvailable = true;
static boolean done = false;

public static boolean isAvailable() {
return isAvailable;
}

public static void setAvailable(boolean isAvailable) {
CPU.isAvailable = isAvailable;
}

static void incrementCLOCK()
{
LTS.checkArrival();
CPU.CLOCK++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Clock Tick: " + CPU.CLOCK);
}

@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("CPU starts.!!!");
while(CPU.done != true)
synchronized(CPU.CLOCK)
{
incrementCLOCK();
}
}
}

Kod dla LTS:

public class LTS implements Runnable
{
private static Process[] pList = null;
private final int NUM;
static Integer procStarted;
static Integer procFinished;
static boolean STSDone = false;


LTS(Process[] pList, int num)
{
this.NUM = num;
LTS.pList = pList;
}

static void checkArrival()
{
if(pList == null) return;
for(int i = 0; i < pList.length; i++)
if(pList[i].isReady())
{
pList[i].procState = State.READY;
System.out.println("Process " + pList[i].pid + " is now ready.");
CPU.ReadyQ.add(pList[i]);
}
}

@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("Long Term Scheduler starts.!!!");
while(LTS.STSDone != true)
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(LTS.STSDone);
System.out.println("LTS ends.!!!");
CPU.done = true;
}
}

Odpowiedzi:

0 dla odpowiedzi № 1

Problem numer 1 polega na tym, że twój współużytkowany stan nie jest bezpieczny dla wątków. Nawet proste rzeczy, takie jak booleany, wymagają prawidłowych operacji podstawowych wątków, aby zapewnić widoczność między wątkami (inaczej „niestabilne”).