Alternierende Ausgabe mit Threads und Semaphoren

Gegeben ist die folgende Klasse Semaphore:

public class Semaphore
{
 private int value;

 public Semaphore(int init)
 {
 if(init
Damit wird kann also das Semaphore-Konzept realisiert werden.

Jetzt soll eine Thread-Klasse konstruiert werden.
Mit dieser ThreadKlasse soll die Folgende Ausgabe realisiert werden (Endlosschleife):

Ich bin der erste
Ich bin der zweite
Ich bin der erste
Ich bin der zweite
... (alternierend also)

Meine Lösung wäre bisher diese hier:


    
    public class Threadclass extends Thread
    {
     private String name;
     private Semaphore s1,s2;
     private int status=0;
    
     public Threadclass(String name)
     {
     this.name=name;
    
     //nachfolgende Initialisierungen korrekt???
     s1=new Semaphore(1);
     s2=new Semaphore(1);
     }
    
     public void run()
     {
     while(true)
     {
     //hier kann Semaphre p() bzw v() genutzt werden
     //um die gewünschte Ausgabe zu erzeugen
    
    
     }
     }
    
    
     public static void main(String[] args)
     {
     Threadclass t1=new Threadclass("Ich bin der erste");
     Threadclass t2=new Threadclass("Ich bin der zweite");
     t1.start();
     t2.start();
    
     }
    
    }




Allerdings weiß ich nicht, wie ich genau mit den Semaphoren umzugehen haben, also wann p() und wann v() verwenden? Ist es überhaupt richtig, hierfür 2 Semaphoren zu verwenden?

Danke für Ihre Hilfe

public class Threadclass extends Thread
{
private String name;
private Semaphore s1,s2;
private int status=0;

public Threadclass(String name)
{
this.name=name;

//nachfolgende Initialisierungen korrekt???
s1=new Semaphore(1);
s2=new Semaphore(1);
}

public void run()
{
while(true)
{
//hier kann Semaphre p() bzw v() genutzt werden
//um die gewünschte Ausgabe zu erzeugen

}
}

public static void main(String[] args)
{
Threadclass t1=new Threadclass(„Ich bin der erste“);
Threadclass t2=new Threadclass(„Ich bin der zweite“);
t1.start();
t2.start();

}

}

Allerdings weiß ich nicht, wie ich genau mit den Semaphoren
umzugehen haben, also wann p() und wann v() verwenden? Ist es
überhaupt richtig, hierfür 2 Semaphoren zu verwenden?

also so wie dus im Moment startest du in deinem Code 2 Threads mit jeweils 2 (insgesamt 4) Semaphoren
Das Semaphor soll aber die Kommunikation deiner beiden Threads gewährleisten, deshalb brauchst du 1 für beide, dass du am besten im Konstruktor übergibst.

p() und v() bieten dir die Möglichkeit, dass immer nur ein Thread etwas tut, während der andere wartet

hoffe ich konnte dir helfen

Hallo und erstmal Danke für deine Hilfe.
Ich habe noch nicht ganz verstanden, wie ich mit dem einen Semaphore dann umzugehen habe. Also wenn maximal ein Thread meinen Kritischen Abschnitt betreten darf, sprich seinen Namen auszugeben, dann muss ich doch dafür den einen Semaphore mit 1 initialisieren, oder?

Andere Frage: Wie ist genau mit p() und v() umzugehen.
Ich geh jetzt davon aus, dass ich die Run()-Mehtode der Thread-Klasse implementieren muss. Wenn ich meine Ausgabe zuerst mache (Name des Thread ausgeben) und dann s.p() mache, wird der nächste Thread anschließend erstmal „schlafend“ gesetzt. Aber woher weiß ich jetzt, dass auch der zweite Therad überhaupt dran kommt? Sprich, ich weiß nicht, wie man es schafft, diese alternierende Ausgabe hinzukriegen…Es gibt ja nur eine einzige Threadklasse, aber 2 Threadobjekte, die diese eine run()-Methode innerhalb dieser Threadklasse ausführen…

um das zu verstehen, gehst du am besten in Gedanken Schritt für Schritt durch, was passiert, wenn du p bzw. v gleichzeitig aufrufst.

der Thread welcher als erstes p aufruft setzt value eins runter und ist dann fertig
der zweite Thread der p aufruft, wartet, weil value nun 0 ist (wenn du den Semaphor mit 1 initialisiert hast)

v dient dann dazu den jeweils anderen Thread wieder aufzuwecken

du musst also deine Ausgabe so einbauen, dass ein Thread wartet, Ausgabe macht, den anderen losschickt und dann wieder wartet

Also angenommen, ich befinde mich in der Run-Methode():

public void run()
{
 while(true)
 {
 //sem.p() aufrufen, damit der erste Thread auf 0 zählt und seine
 Ausgabe macht und der zweite Thread wartet
 sem.p();
 System.out.println(sem.getName());
 //jetzt MUSS der Wartende Thread seine Ausgabe machen
 //d. h. ich muss mit sem.v() den wartenden Thread wecken
 sem.v();
 ///PROBLEM: Woher weiß ich nun, dass auch der gerade aufgeweckte 
 Thread an die Reihe kommt??? Es könnte doch auch wieder der erste an
 die Reihe kommen, weil der ja nie blockiert wurde...
 ...
 }
}

//sem.p() aufrufen, damit der erste Thread auf 0 zählt und
seine
Ausgabe macht und der zweite Thread wartet
sem.p();
System.out.println(sem.getName());
//jetzt MUSS der Wartende Thread seine Ausgabe machen
//d. h. ich muss mit sem.v() den wartenden Thread wecken
sem.v();
///PROBLEM: Woher weiß ich nun, dass auch der gerade
aufgeweckte
Thread an die Reihe kommt??? Es könnte doch auch wieder der
erste an
die Reihe kommen, weil der ja nie blockiert wurde…

ja das Problem ist mir auch schon aufgefallen
und bisher weiß ich nicht recht, wie man das mit diesem Synchronisationskonzept macht.
Wenn mir noch was sinnvolles einfällt, schreibe ichs dir

Deine Threads sind nun mal Kettenglieder eines Graphs geworden

[0]->[1]->…->[length-1] -

/\ |
|____…________|

Für jede Kante(Pfeil) gibt es eine „Semaphore“.
Für jedes Kettenglied ([x]) einen „Link“.

Alle Semaphoren werden mit 0 initialisiert, so sind alle Link zum
warten verdonnert.
Die Sempahore von [lenght-1] zu [0], muss mit 1 initilisiert werden,
dies ist der Startpunkt, der erste der nicht warten muss.

Die links deaktivieren in ihrer run Methode jeweils
ihre Vorgänger und aktivieren ihren jeweiligen Nachfolger.

Nebenbei:
Wenn man statt einem Vorgänger/Nachfolger, mehrere ermöglicht, z.B. per
Array, lassen sich statt Ketten, komplexe Graphen aufbauen.
Damit hätte man dann ein einfaches Petri Netz.

/\* Kette \*/ 
public class Chain {
 public static void main(String[] args) { 
 Chain g = new Chain(4); //Kette mit 4 Gliedern
 g.start();
 try{
 Thread.sleep(200);
 }catch( InterruptedException e){
 }finally{
 g.interrupt();
 }
 }

 /\* Kettenglied \*/
 private static class Link extends Thread {
 private Semaphore pre; //Eingehende Kante
 private Semaphore post; //Ausgehende Kante

 public Link( int member, Semaphore pre, Semaphore post){
 super("Link "+member);
 this.setDaemon(true);
 this.pre = pre;
 this.post= post;
 }

 public void run(){
 while( !this.isInterrupted() ){
 pre.p();
 System.out.println(this.getName());
 post.v();
 }
 }
 }

 /\* Kettenglieder \*/
 private Link[] link;

 /\* Jede Semaphore steht für eine Verbindung in der Kette
 \* s[0] verbindet link[0] und link[1],
 \* s[semaphores-1] verbindet link[link-1] mit link[0] \*/
 private Semaphore[] semaphores;

 public Chain(int chainLength){
 if( chainLength