2017-04-07 15 views
1

Ich habe eine knifflige Zeit zu verstehen, wie man die Kontrolle zwischen zwei Prozessen mit Semaphoren wechseln. Hier ist ein künstliches Beispiel für den Prozessbehandlungscode.Synchronisieren von Prozessen mit Semaphoren

int pid = fork(); 

if (pid) { 
    int counter = 0; 
    while (true) { 
    counter += 1; 
    printf("P%d = %d", pid, counter); 
    } 
} else { 
    int counter = 0; 
    while (true) { 
    counter += 1; 
    printf("P%d = %d", pid, counter); 
    } 
} 

Ich erwarte den obigen Code parallel laufen zu lassen, aber es scheint wie Kontrollfluss sofort für den gegabelten Prozess wird fortgesetzt, und erst später wieder für den übergeordneten Prozess.

Dies ist grundlegend brechen meine bestehenden Code, der ein Semaphor verwendet, um zu steuern, welcher Prozess kann handeln.

int id = get_semaphore(1); 
int pid = fork(); 

if (pid) { 
    int counter = 0; 
    while (true) { 
    sem_wait(id); 
    counter += 1; 
    printf("P%d = %d\n", pid, counter); 
    sem_signal(id); 
    } 
} else { 
    int counter = 0; 
    while (true) { 
    sem_wait(id); 
    counter += 1; 
    printf("P%d = %d\n", pid, counter); 
    sem_signal(id); 
    } 
} 
  • Der sem_wait helper subtrahiert nur 1 von dem Semaphor-Wert und blockiert, bis das Ergebnis> 0 ist (verwendet semop unter der Motorhaube).

  • Der Helfer sem_signal fügt nur 1 zum Semaphorwert hinzu (verwendet semop unter der Haube).

würde ich der Code wie zwischen den beiden Prozessen zu wechseln, sem_wait mit den anderen Verfahren, die Ressourcen mit sem_signal Mitteilungen zu blockieren, bis. Die gewünschte Ausgabe wäre:

P1 = 0 
P0 = 0 
P1 = 1 
P0 = 1 
... 

jedoch wegen der anfänglichen Ausführungsverzögerung zwischen den Prozessen, nimmt das Kind Prozess die verfügbare Semaphor Ressource, verwendet es eine Reihe zu drucken, stellt sich wieder her, dann und Schleifen - wobei an diesem Punkt Die Ressource ist wieder verfügbar und wird fortgesetzt, ohne jemals auf den anderen Prozess zu warten.

Was ist der beste Weg, um zu verhindern, dass ein Prozess Ressourcen verwendet, wenn er sie selbst freigegeben hat?

+0

Sie benötigen zwei Semaphore und eine 'executeNow'-Einheit. Führen Sie die Einheit zwischen den Prozessen hin und her. – ThingyWotsit

Antwort

1

Semaphore haben zwei allgemeine Anwendungsfälle. Einer ist der gegenseitige Ausschluss und der zweite ist die Synchronisation. Was in Ihrem Code getan wurde, ist der gegenseitige Ausschluss. Was Sie eigentlich wollen, ist die Synchronisation (Alternierung) zwischen den Eltern- und Kind-Prozessen.

Lassen Sie mich ein wenig erklären:
Mutual Ausschluss bedeutet, dass nur jederzeit einmal Prozess einen „kritischen Bereich“, der ein Stück Code ist zugreifen können, die Sie nur ein Prozess/Thread für den Zugriff auf einen time.Critical wollen Abschnitte enthalten in der Regel einen Code, der eine freigegebene Ressource bearbeitet.

In Ihrem Code, da Sie nur einen einzigen Semaphor verwendet haben, gibt es keine Garantie für die "Reihenfolge", in der jeder Prozess den kritischen Abschnitt betreten darf. ex: sem_wait (id) aus Ihrem Code kann von jedem Prozess ausgeführt werden und es ist nicht notwendig, dass die beiden Prozesse wechseln sollten.

Für die Prozesssynchronisierung (insbesondere Alternation) müssen Sie zwei Semaphore für Eltern und eine andere für Kind verwenden.

Sample code: 
    int pid = fork(); 

    int parent_sem = get_semaphore(0); 
    int child_sem = get_semaphore(1); 

    if (pid) { 
     int counter = 0; 
     while (true) { 
      sem_wait(child_sem); 
      counter += 1; 
      printf("P%d = %d", pid, counter); 
      sem_signal(parent_sem); 
     } 
    } else { 
     int counter = 0; 
     while (true) { 
      sem_wait(parent_sem); 
      counter += 1; 
      printf("P%d = %d", pid, counter); 
      sem_signal(child_sem); 
     } 
    } 

Sie müssen einen Semaphor (in meinem Fall Kind) zu 1 und den zweiten zu Null initialisieren. Auf diese Weise kann nur einer der beiden Prozesse beginnen, während der andere in die Warteschleife geht. Sobald das Kind fertig gedruckt ist, signalisiert es dem Elternteil. Der Semaphorwert des Kindes ist nun Null, so dass er auf wait (child_sem) wartet, während der Elternteil, der vom Kind signalisiert wurde, ausgeführt wird. Das nächste Mal signalisiert Eltern Kind und es wird ausgeführt. Dies setzt sich in alternierenden Sequenzen fort und ist ein klassisches Synchronisationsproblem.

+0

Es sieht aus wie dieser Code genau das gleiche Verhalten hat. Ich habe eine 'printf'-Anweisung am Anfang des 'else'-Zweiges, die erst angezeigt wird, nachdem die while-Schleife des Kindes einige Male gelaufen ist. Hört sich an, als wäre das Problem eher die E/A als die Semaphore. –

1

es wie Kontrollfluss scheint weiterhin sofort für den gegabelten Prozess wird erst fortgesetzt, später für den übergeordneten Prozess

Das heißt, da Strom IO die Ausgangspuffer auf stdout bis entweder

  • der Puffer ist voll
  • fflush() ist angerufen stdout
  • ein Newline (\n) angetroffen wird

In Ihrem Programm wird jeder Prozess einen Puffer füllen, bevor dessen Inhalt stdout Senden geben die Aussehen eines Prozesses für eine lange Zeit läuft, dann die andere. Beende die Formatzeichenfolgen deiner printf-Anweisungen mit \n und du wirst das Verhalten in deinem ersten Programm mehr wie erwartet sehen.

Ich bin mir nicht sicher, warum Ihre Semaphor-Sache nicht funktioniert - ich bin nicht sehr gut informiert über System V-Semaphoren, aber es scheint wie eine rote Fahne, dass Sie die Semaphore bekommen, nachdem Sie gespalten haben. Bei den üblicheren POSIX-Semaphoren muss der Semaphor im Speicher sein, den beide Prozesse sehen können, sonst sind es zwei Semaphoren.

Wie auch immer, vorausgesetzt, Ihre get_semaphore() Funktion tut das Richtige, um den Semaphor zu teilen, gibt es immer noch ein Problem, weil es keine Garantie gibt, dass wenn ein Prozess den Semaphor signalisiert, der andere früh genug damit beginnen wird noch einmal, bevor der erste Prozess sich umschlingt und ihn selbst ergreift.

Sie benötigen zwei Semaphoren, einen für den Elternteil und einen für das Kind. Vor dem Druck sollte jeder Prozess auf seinen eigenen Semaphor warten. Nach dem Druck sollte jeder Prozess den anderen Semaphor signalisieren. Außerdem sollte ein Semaphor mit einer Zählung von 1 initialisiert werden und der andere sollte mit einer Zählung von 0 initialisiert werden.

+0

Tut mir leid, ich habe ein bisschen schlampig über das erfundene Beispiel, in Wirklichkeit bekomme ich den Semaphor, bevor ich mit Zeilenumbrüchen drucken und drucken kann. Die Frage wurde aktualisiert. –

+0

Es wurde versucht, einen Prozess auf stdout und den anderen auf stderr zu drucken, aber es scheint, als ob der untergeordnete Prozess noch lange läuft, bevor der übergeordnete Prozess fortgesetzt wird. –

Verwandte Themen