2008-10-30 12 views
5

Ich habe eine einzige HW-Schnittstelle, die ich aus zwei Anwendungen (Prozesse) auf der gleichen Arbeitsstation verwenden möchte. Die HW erfordert einen einzigen Initialisierungsaufruf, dann verwendet jede App die gleiche Funktion (in derselben Bibliothek), um viele Transaktionen mit der HW durchzuführen.Wie synchronisiere ich zwei Prozesse?

So sollte jede App so handeln:

main() 
    // I don't know if another app already init'ed the HW 
    ret = hw_init_lock(non-blocking) 

    if ret = OK 
     // no one else has done this, I have to 
     init_hw() 
    else 
     //someone else has already init'ed the HW, I gotta make sure it stays that way 
     //as long as I'm alive 
     increment_hw_init_ref_counter() 

    hw_trans_lock(blocking) 
    hw_trans() 
    hw_trans_unlock() 
    .... 

    //exit app, uninit hw if we are last out 
    ret = decrement_hw_init_ref_counter() 
    if ret == 0 
     uninit_hw() 

    exit(0) 

Was ist der Mechanismus ich in den Lock und Referenzzähler Anrufe verwenden können, die zwischen zwei Anwendungen gemeinsam genutzt wird? Ich denke Named Pipes, d. H. Mkfifo().

Antwort

2

Da Sie nur eine Semaphorzahl von eins benötigen, genügt ein Mutex.

+4

POSIX Semaphore können über unabhängige Prozesse geteilt werden, während Pthread mutexes nicht. – ephemient

9

POSIX semaphore ist der Weg zu gehen. Da Sie die gleiche Semaphor über Prozesse gemeinsam nutzen möchten, müssen Sie ein Semaphor genannt verwenden .:

Eine benannte Semaphore von einem Namen des Formulars/somename identifiziert wird. Zwei Prozesse können auf demselben genannten Semaphor betrieben werden, indem derselbe Name an sem_open (3) übergeben wird.

1

Ich gehe davon aus, dass

... dass zwischen zwei Anwendungen gemeinsam genutzt wird?

bedeutet, dass diese beiden Dinge als separate Prozesse ausgeführt werden sollen? Wenn das nicht stimmt und sie als ein einzelner Prozess (mit mehreren Threads) ausgeführt werden, dann sind die Vorschläge von Semaphoren und Mutexen die beste Option und sollten ziemlich einfach sein.

Beachten Sie, dass die Antwort davon abhängt, wie genau Sie auf diese Hardware zugreifen. Wenn es beispielsweise über eine Datei verfügbar gemacht wird, kann die normale Dateisperre verwendet werden.

Wenn Sie jedoch versuchen, den Zugriff auf die Hardware über zwei Prozesse zu synchronisieren, ist das eine andere Sache. Ich denke, das erste, was zu sagen ist, dass es einfacher zu synchronisieren ist, wenn Sie können, einen einzigen Prozess für den Zugriff auf die Hardware zu haben. In diesem Modell haben Sie möglicherweise einen Prozess, der als Server für die Hardware fungiert - indem Sie Anforderungen von anderen Prozessen akzeptieren und die Lese- und Schreibvorgänge für sie ausführen. Fast jede Form von Interprozesskommunikationen ist geeignet, aber der Einfachheit halber kann etwas wie die Nachrichtenwarteschlange (link) mit einer geeigneten Datenstruktur geeignet sein (z. B. ein Flag, um anzuzeigen, ob es eine Lese- oder Schreiboperation ist, Offset von der Basisadresse) Ihrer Hardware, Anzahl der Bytes, Puffer (im Falle eines Schreibvorgangs))

Wenn es nicht angebracht ist, den gesamten direkten Hardwarezugriff in einem einzigen Prozess zu verwenden, müssen Sie ein geeignetes Synchronisierungsschema verwenden. Ich würde die Verwendung von entweder Dateisperren (und implementieren ein rudimentäres Mutex Schema) oder mit dem Namen Semaphore untersucht

4

Semaphore und Mutex/Zustandsgrößen sind gut, sehr leistungsfähige Grundelemente, die geeignet sind (wie albertb vorgeschlagen hat) zur Verwendung zwischen Threads oder zwischen Prozessen.

Alle diese basieren auf der Idee (und in der Regel auf der Realität) von Test-and-Set oder anderen atomaren Operationen, die auf gemeinsam genutztem Speicher ausgeführt werden.

Wenn Sie Ihre Prozesse über das Netzwerk verteilen möchten, sind Semaphore und Mutexe möglicherweise nicht für Sie geeignet - sie funktionieren nur auf einem einzigen Computer. Pipes und Sockets sind in der Regel Netzwerk-erweiterbar.

Eine kurze Zusammenfassung der Mutexe, Bedingungsvariablen und Semaphore:

Mutexes

Ein Mutex ist eine primitive, die entweder gesperrt werden kann, oder entriegelt. Der Prozess/Thread, der es gesperrt hat, muss derjenige sein, um es zu entsperren. Dieser Besitz Aspekt ermöglicht dem Betriebssystem, einige interessante Optimierungen anzuwenden, wie Prioritätsvererbung und Priority-Ceiling-Protokoll (um Prioritätsinversion zu vermeiden). jedoch, dem Mutex ist keine Zählung zugeordnet. Sie können einen bereits gesperrten Mutex im Allgemeinen nicht sperren und behalten Speicher, dass es "doppelt gesperrt wurde" (es gibt einige Erweiterungen, die dies zulassen, denke ich, aber sie sind nicht überall verfügbar)

Bedingung Variablen

Ein Mutex ist ideal für ... gut, MUTual Exclusion. Aber was, wenn Sie eine Bedingung blockieren müssen, die mit dem Objekt verbunden ist, zu dem Sie sich gegenseitig ausschließen? Dazu verwenden Sie eine Bedingungsvariable oder CV. Ein Lebenslauf ist mit einem Mutex verbunden. Angenommen, ich habe eine Warteschlange mit Eingabedaten, auf die meine Prozesse zugreifen möchten. Man greift nach dem Mutex, damit er ohne Angst vor Störungen in die Warteschlange schauen kann. Es findet jedoch die Warteschlange leer und möchte warten, dass etwas in die Warteschlange kommt. Es wartet daher auf die Zustandsvariable "Warteschlange nicht leer". Der interessante Teil hier ist, dass, weil der CV dem Mutex zugeordnet ist, der Mutex automatisch wieder erlangt wird, sobald die Zustandsvariable signalisiert wird. Sobald der Prozess aufwacht, nachdem er auf den CV gewartet hat, weiß er, dass er exklusiven Zugriff auf die Warteschlange hat. Was es macht nicht wissen ist, ob die Warteschlange wirklich etwas hat - vielleicht zwei Prozesse auf den Lebenslauf gewartet - eine Sache kam - und die erste Priorität kam in und die Warteschlange "das Ding", bevor die zweite Sache erwachte oben. So, wenn Sie einen Lebenslauf zu verwenden, müssen Sie die Bedingung noch einmal zu überprüfen, wie folgt aus:

mutex_enter(m); 
while (! condition) { 
    cond_wait(m, c); // drop mutex lock; wait on cv; reacquire mutex 
} 
//processing related to condition 
mutex_exit(m); 

Semaphore

OK, dass Mutexe und Bedingungsvariablen ist. Semaphore sind einfacher. Sie können von beliebigen Prozessen inkrementiert und dekrementiert werden. Sie haben Speicher - sie zählen - damit können Sie feststellen, wie viele Bedingungen aufgetreten sind. Nicht so bei Zustandsvariablen. Da Semaphore auch um einen Prozess dekrementiert und um einen weiteren erhöht werden können, haben sie nicht den Eigentumsaspekt - also ist keine Prioritätsvererbung, keine Prioritätsinversionsvermeidung möglich.

Jetzt, endlich - all diese Mechanismen erfordern gemeinsamen Speicher für eine effiziente Implementierung. Dies kann für Sie in Ordnung sein, aber seien Sie sich bewusst - wenn Sie glauben, dass Ihre Anwendung möglicherweise verteilt wird, dann sind Mutexe, Zustandsvariablen und Semaphore möglicherweise nicht für Sie. Pipes und Sockets haben, obwohl sie viel mehr Overhead haben, die Möglichkeit, über das Netzwerk ziemlich einfach ausgedehnt zu werden.