2012-03-01 10 views
3

私はこのトピックに関する私の混乱を解決したいと思っていました。シンプルに聞こえるかもしれませんが、本当に混乱しています。ミューテックスとセマフォを使用して共有データを操作する

プロデューサ/コンシューマの問題では、4セマフォのソリューションを使用しました。クリティカルセクションごとに異なるロックを使用しました。 言って、私はプロデューサーに「mutex1」として、私の消費者のための第二ミューテックスとして、「mutex2」を使用

Pseudo code of producer: 
    wait(slot) // counting sem 
     wait(mutex1) // binary sem 
     rear <-- rear + 1 
     buffer[rear] <-- item 
     signal (mutex1) 
    signal(items) 

今、私の質問です。私のプロデューサーとコンシューマーがバッファー(リアとフロント)を使用せず、スタックを使用している場合、彼らだけが[トップ]を操作できます。相互排除を確実にするために、私の4セマフォと同じ1つのmutexまたは2つの異なるロックを使用する必要がありますか?

Pseudo code of consumer with stack: 
     wait (message) 
      wait (mutex) 
       getspace <-- stack[top] 
       top – 1 
      signal (mutex) 
      signal (slot) 

個人的に私は両方の手順に1つのロックが必要だと思うので、プロデューサとコンシューマのどちらもトップに同時にアクセスしないようにします。しかし、それについては分かりません。 ありがとうございます。

答えて

2

私はあなたの擬似コードに従うことを100%保証しているわけではありませんが、セマフォを使用してProducer-consumerプロセス内からスタックを管理する方法を説明するために最善を尽くします。

複数のスレッドにまたがってアクセスされているスタックがある場合、データがアクセスされているとき、具体的にはプッシュおよびポップされているときにロックする必要があります。これは常にプロデューサ - 消費者問題の根本的な前提です。

まず、スタックをロックするために使用するミューテックスを定義します。私たちは消費者と生産者のスレッドでそれからのデータを追加または削除された場合

プロセスのグローバル宣言セマフォ

stackAccessMutex = semaphore(1) # The "(1)" is the count 
           # initializer for the semaphore. 

次に、我々はそれをロックする必要があります。

プロデューサーのスレッド

dataPushBuff #Buffer containing data to be pushed to the stack. 

…dataPushBuff is assigned… 

stackAccessMutex.wait() 
    stack.push(dataPushBuff) 
stackAccessMutex.signal() 

消費者スレッド

dataRecvBuff = nil # Defining a variable to store the pushed 
        # content, accessible from only within 
        # the Consumer thread. 

stackAccessMutex.wait() 
    dataRecvBuff = stack.pop() 
stackAccessMutex.signal() 

…Consume dataRecvBuff as needed since it's removed from the stack… 

はこれまでのところ、すべてはかなり単純です。プロデューサは必要なときにのみスタックをロックします。同じことが消費者にも当てはまります。別のセマフォーは必要ありませんか?正しい?何も間違っていません!

上記のシナリオでは、スタックがポップされる前に常にデータで初期化されるという致命的な仮定があります。プロデューサスレッドがデータをポップする機会を得る前にコンシューマスレッドが実行されると、stack.pop()は何も返されないため、コンシューマスレッド内にエラーが生成されます。これを修正するには、消費者に、データがスタック内で利用可能であることを知らせる必要があります。

まず、スタック内のデータが存在するかどうかを知らせるために使用できるセマフォを定義する必要があります。プロセスのセマフォの

グローバル宣言、バージョン#2

stackAccessMutex = semaphore(1) 
itemsInStack  = semaphore(0) 

我々は(1を参照)0 である私達のスタック内のアイテムの数に私たちのitemsInStackを初期化します。

次に、新しいセマフォをProducerおよびConsumerスレッドに実装する必要があります。まず、アイテムが追加されたことをProducerの信号で確認する必要があります。今プロデューサーを更新しましょう。

プロデューサースレッド、我々は、スタック内のデータがセマフォを経由してあるかどうかをチェックできるようになったので、バージョン#2

dataPushBuff 

…dataPushBuff is assigned… 

stackAccessMutex.wait() 
    stack.push(dataPushBuff) 
stackAccessMutex.signal() 
itemInStack.signal() #Signal the Consumer, we have data in the stack! 
        #Note, this call can be placed within the 
        #stackAccessMutex locking block, but it doesn't 
        #have to be there. As a matter of convention, any 
        #code that can be executed outside of a lock, 
        #should be executed outside of the lock. 

、私たちの消費者のスレッドを再書いてみましょう。

消費者スレッド、バージョン#2

dataRecvBuff = nil # Defining a variable to store the pushed 
        # content, accessible from only within 
        # the Consumer thread. 

itemsInStack.wait() 
stackAccessMutex.wait() 
    dataRecvBuff = stack.pop() 
stackAccessMutex.signal() 

…Consume dataRecvBuff as needed since it's removed from the stack… 

...とそれはそれです。表示されているように、2つのセマフォがあり、両方ともの場合はにスタックをロックする必要があるため、両方のセマフォが必須です(2参照)。データが利用できるときにコンシューマーに通知し、スタック

ご質問にお答えします。特定の質問がある場合は、私の回答を更新します。

  1. 処理が開始されると、理論的には、データが事前に初期化し、あなたのスタックを ことができます。この場合、 になります。 は、 の値をスタックカウントと同じ値でitemsInStackセマフォを初期化する必要があります。ただし、この例の場合、 はスタックにデータがないと仮定しており、 は初期化しません。

  2. それは1の下で、特定の状況はあなたが 理論的にはちょうどstackAccessMutexを使用して離れて得ることができることを言及する価値があります。 スタックに常にデータが含まれている場合を考えてみましょう。 スタックが無限である場合、常にデータが存在するため、データ が追加されたことをコンシューマに通知する必要はありません。しかし、 では、実際には「無限のスタック」は存在しません。たとえそれが現在の状況で である場合でも、 itemsInStackセマフォのセーフティネットを追加する際のオーバーヘッドはありません。

    また、空のスタック上の任意の データを返さないとしたら stack.pop()の呼び出しがエラーを起こさない現在の状況下であれば セマフォを数えるitemsInStackを捨てるためにしたくても良いです。

    これは可能ですが、お勧めしません。コンシューマスレッドがループ上で コードを実行していると仮定すると、ループはスタック消費コードを継続的に実行し、 は消費するデータがありません。itemsInStackセマフォを使用すると、データが到着するまでに スレッドを一時停止します。これにより、CPUサイクルが数回節約されます。

関連する問題