Race Condition mittels Semaphore verhindern

BodyLAB

Bekanntes Mitglied
Hallo zusammen,

ich habe folgenden Pseudocode erhalten: (Es soll beantwortet werden ob eine Race Condition eintritt und wo)
Code:
public enum Action{open, close}
Action action; //global definiert

//Lichtschranke                                    //Türsteuerung
while(...) {                                    while(..) {
    if(activated())                                    if(action == Action.open)
        action = Action.open;                            door.open()
    else                                            else
        action = Acion.close;                            door.close()
}                                                }

Nun kann hierbei eine Race Condition auftreten, action ist global Definiert. Somit existiert nur ein Objekt für die Lichtschranke und die Türsteuerung. Das Datenelement wird sowohl geschrieben als auch gelesen, das würde schon eine Synchronisation nötig machen. Die Race Condition tritt hier jedoch bei beiden in der while Schleife ein. Die Lichtschranke schreibt action und zur gleichen Zeit kann es passieren das die Türsteuerung in der if Abfrage action lesen möchte. Wenn nun die Lichtschranke zu erst dran kommt und zwischenzeitlich bevor zu ende geschrieben werden konnte ein Threadwechsel passiert liest die Tür einen Falschen wert.

Das wäre erst einmal meine Antwort.

Nun geht es aber weiter und da komme ich nicht ganz mit.

Code:
public class Semaphore { //Mutex
void p() {}
void v() {}
}
...
Semaphore s = new Semaphore();
...
//Lichtschranke
s.p();
while(...) {
if(activated()) action = Action.open;
else action = Action.close;
}
s.v();

//Türsteuerung
s.p();
while(...) {
if(action == Action.open) door.open();
else door.close();
}
s.v();

Wenn ich das jetzt korrekt verstehe ist der Semaphore nicht Global Definiert. Somit hätte jede Klasse (Objekt) dann seinen eigenen Semaphore. Dann bringt diese ändern überhaupt nichts oder 😀 Der Semaphore würde bei s.p() runtergezählt werden, der Kritische Abschnitt betretten werden und einfach wieder verlassen werden über s.v();. Davon bekommt das jeweils andere Objekt nichts mit. Die Race Condition wäre damit nicht beseitigt.

Über sehe ich hierbei etwas? Birgt diese Semaphore Implementierung noch irgendwelche Nebeneffekte (Fehler)?

😳
 
Schaue dir das mal an das was du machst hat mit dem Semaphore nicht viell zu tun.
Das habe ich ja auch nicht selbst gemacht.
Diese zwei oben gezeigten Code Beispiele habe ich bekommen und die Fragen sind:

Tritt im ersten Fall eine Race Condition auf. Meine Antwort befindet sich direkt drunter. Kurz um JA es tritt eine Race Condition auf.
Dann sollte es verbessert werden über die Semaphore.
Doch dabei Blicke ich eben nicht ganz durch denn wenn der Semaphore ja in der jeweiligen Klasse sich befindet bringt es nicht viel. Er müsste doch geteilt werden, also das beide Klassen Schranke wie auch Tür mit dem selben Semaphore arbeiten.

Darum geht es im Prinzip.
 
So hab mir die Aufgabe geben lassen.

Gegeben ist der Prozess Lichtschranke, der fortlaufend die Lichtschranke einer elektronischen Tür überprüft. Falls die Lichtschranke auslöst, schreibt er den Befehl „open“ in die globale Variable action (bzw. „close“ wenn die Lichtschranke ungestört ist). Der Prozess Türsteuerung liest diese Variable und führt die geforderte Aktion aus. Nachfolgend sind die Steuerungen der beiden Prozesse auszugsweise aufgeführt:
Code:
public enum Action{open, close}
Action action; //global definiert

//Lichtschranke                                    //Türsteuerung
while(...) {                                    while(..) {
    if(activated())                                    if(action == Action.open)
        action = Action.open;                            door.open()
    else                                            else
        action = Acion.close;                            door.close()
}                                                }

1. Kann hierbei eine race condition auftreten? Falls ja, erklären Sie wo und wie dies passiert
2. Ein Programmierer hat versucht, die race conditions zu verhindern, indem er Semaphore in den Quellcode eingebaut hat. (Siehe Code unten) Treten jetzt immer noch race conditions auf? Erkennen Sie ein Problem, das durch das Setzen der Semaphore aufgetreten ist?

Code:
public class Semaphore { //Mutex
void p() {}
void v() {}
}
...
Semaphore s = new Semaphore();
...
//Lichtschranke                                    //Türsteuerung
s.p();                                            s.p();
while(...) {                                    while(...) {
if(activated()) action = Action.open;            if(action == Action.open) door.open();
else action = Action.close;                        else door.close();
}                                                }
s.v();                                            s.v();

Somit geht es hier nur um die zwei Fragen oben und alles andere ist reiner Pseudocode.
Ich würde eben Frage eins sowie zwei so beantworten:

1. Nun kann hierbei eine Race Condition auftreten, action ist global Definiert. Somit existiert nur ein Objekt für die Lichtschranke und die Türsteuerung. Das Datenelement wird sowohl geschrieben als auch gelesen, das würde schon eine Synchronisation nötig machen. Die Race Condition tritt hier jedoch bei beiden in der while Schleife ein. Die Lichtschranke schreibt action und zur gleichen Zeit kann es passieren das die Türsteuerung in der if Abfrage action lesen möchte. Wenn nun die Lichtschranke zu erst dran kommt und zwischenzeitlich bevor zu ende geschrieben werden konnte ein Threadwechsel passiert liest die Tür einen Falschen wert.
Bei Punkt 2 stellt sich eben die Frage wie ist das ganze Aufgebaut. Wenn wir hier von zwei Klassen Sprechen und einem geteilten Semaphore sollte es doch Funktionieren. Wenn jedoch es zwei Klassen sind und in jeder Klasse wird ein eigener Semaphore definiert klappt es wieder nicht. Hier mal so wie ich es mir vorstelle als Code Beispiel:
Java:
public class Lichts {
    
    Action action;
    
    public Lichts(Action a) {
        action = a;
    }
    
    public class Semaphore {
        void p() {}
        void v() {}
    }
    
    public static void main(String[] args) {
        ...
        Semaphore s = new Semaphore();
        ...
        s.p();
        while(...) {
            if(activated())
                action = Action.open;
            else
                action = Action.close;
        }
        s.v();
    }
}

Java:
public class Tür {
    
    Action action;
    
    public Tür(Action a) {
        action = a;
    }
    
    public class Semaphore {
        void p() {}
        void v() {}
    }
    
    public static void main(String[] args) {
        ...
        Semaphore s = new Semaphore();
        ...
        s.p();
        while(...) {
            if(action == Action.open)
                door.open();
            else door.close();
        }
        s.v();
    }
}

Dadurch hätten wir eine Globale Action Variable und die Semaphore haben nichts miteinander zu tun wodurch sie Sinnlos wären.
Der Kritische Abschnitt die Race Condition wäre nicht behoben.

So hätte ich das ganze nun verstanden. Ich kann mich auch irren, außerdem Verstehe ich eben dann auch nicht was für ein Problem jetzt entstehen würde wenn man dort Semaphore so nutzen würde?
 
Ich gehe mal davon aus das die while Schleife in der run vom Thread ist.
Und das die while fast eine endlos Schleife ist.

Wenn du vor der while Schleife s.p() machst, somit denn folge code schützt.
Du aber aufgrund der endlos Schleife nie zum wieder freigeben kommst s.v().

Hat es dann einen Sinn?

Wenn du dir das Code Beispiel der Insel anschaust wo macht er da den Schutz?
 
Zuletzt bearbeitet:
Hat es dann einen Sinn?
Nein Überhaupt nicht. Weil ich auch nichts mit dieser Aufgabe Anfangen kann hab ich es hier gepostet ^.^

Also das erste was ich sehr merkwürdig finde ist, das oben steht die enum class ist Global Definiert.
Beim Semaphore steht das nicht!

Würden wir nun alles in eine Klasse Schreiben, bräuchte man diese Information nicht (vielleicht soll das nur verwirren). Stellen wir uns nun aber einmal vor es steht alles in einer Klasse. Was macht das für einen Sinn? Wenn wir davon ausgehen das beide while Schleifen Endlos laufen macht das ganze null Sinn oder irre ich mich?
Hier mal skiziert:
Java:
public class Main {
    
    Action action;
    
    public Main(Action a) {
        action = a; //könnte man ja nun auch einfach in der main Methode erstellen ich lass es mal hier stehen
    }
    
    public class Semaphore {
        void p() {}
        void v() {}
    }
    
    public static void main(String[] args) {
        ...
        Semaphore s = new Semaphore();
        ...
        s.p();
        while(...) { //sicherlich eine Endlosschleife
            if(action == Action.open)
                door.open();
            else door.close();
        }
        s.v();
        
        s.p();
        while(...) {//sicherlich eine Endlosschleife
            if(action == Action.open) door.open;
            else door.close();
        }
        s.v();
    }
}

Selbst wenn wir es in einen Thread schreiben und in die run Methode, würde es ja nicht anders aussehen nur der Aufruf wäre ein anderer.

Das bedeutet, so wird es sicherlich nicht gedacht sein.

Wir haben also sicherlich zwei Klassen. Vielleicht geht es aber auch gar nicht so sehr darum wie die Klassen auszusehen hätten sondern nur um die Grund Problematik.

Die Grund Problematik wäre ja das eine Race Condition existiert. Wenn wir nun einen einzigen Semaphore nutzen hätten wir keine Änderung in meinen Augen. Es steht dort noch das wir uns damit eher ein Problem einkaufen doch das sehe ich derzeit leider nicht! (vielleicht ja jemand von euch).

Müsste man diese Problematik verbessern könnte man ja "einfach" Argumentieren man nimmt statt einen Mutex eben zwei und überkreuzt diese (weiß nicht ob man das so nennt 😀).

Code:
public class Semaphore { //Mutex
void p() {}
void v() {}
}
...
Semaphore s1 = new Semaphore(1);
Semaphore s2 = new Semaphore(0);
...
//Lichtschranke                                    //Türsteuerung
s1.p();                                            s2.p();
while(...) {                                    while(...) {
if(activated()) action = Action.open;            if(action == Action.open) door.open();
else action = Action.close;                        else door.close();
}                                                }
s2.v();                                            s1.v();

Damit wäre in diesem Code Beispiel doch das Problem beseitigt. Vermutlich denken wir derzeit zu viel wie man es "wirklich" Lösen würde?

Könnte das so sein?
 
Bei dem Ursprungs Code. Würde nur ein thread arbeiten. Der erste macht die Schranke zu vor der while arbeitet dann.
Der zweite wartet vor der while vergebens.
 
Nein wenn dann muss s.p() und s.v() in die while nicht außerhalb.
😱 stimmt.
Hätten wir dann oben wenn es nur ein Mutex gibt und dieser Außerhalb der while Schleife geschrieben wird nicht sogar eine Sperre? So gesehen gewinnt der erste der durch den Mutex kommt und dieser läuft endlos in seiner While Schleife rum. Der andere verhungert doch dann. ODER?
 
😱 stimmt.
Hätten wir dann oben wenn es nur ein Mutex gibt und dieser Außerhalb der while Schleife geschrieben wird nicht sogar eine Sperre? So gesehen gewinnt der erste der durch den Mutex kommt und dieser läuft endlos in seiner While Schleife rum. Der andere verhungert doch dann. ODER?
Habe ich doch schon gesagt.
 
Ach so, ja denn habe ich ja gelesen und jetzt erst die Aufgabe an sich verstanden. So macht es ja schon "Sinn" 🙂
Danke nochmals 😎
 

Neue Themen


Zurück
Oben