2.15プロデューサーの消費者の問題
ダイクストラの同期問題の抽象化
抽象解釈
- 1つ以上のプロデューサーがリソースを生成し、それらをクリティカルセクションに配置します
- 一度に1人のコンシューマーのみがクリティカルセクションにアクセスし、リソースを消費します
- 一度に1人の生産者/消費者だけがクリティカルセクションを訪問します
- クリティカルセクションがいっぱいになると、プロデューサーはリソースを追加し続けません
- クリティカルセクションが空の場合、消費者はリソースを消費し続けません
フローチャート
空間セマフォを使用して、スペースがあるかどうかをプロデューサーに通知
するにはリソースセマフォを使用して、リソースがあるかどうかをコンシューマーに通知するには
2.15.1生産者/消費者問題の要点
- 最初にリソースを申請し、次に相互排除を申請します。順序を逆にすることはできません。それ以外の場合、コンシューマーP0が相互排除を申請し、リソースを待機するとします。プロデューサーP1はリソースを生成する必要がありますが、相互排除を申請してクリティカルエリアに入ることができません。 、デッドロックの形成
- ミューテックスを最初に解放し、リソースを最初に解放しても効果がないため、同じプロセスのスペースとリソースのsemSignalステートメントを逆にすることができます。他のプロセスは2つのセマフォを待機する必要がありますが、パフォーマンスが低下する可能性があるため、通常はリソースを解放します。最初にミューテックスを解放します
- 同じセマフォの待機とシグナルは、リソースセマフォなどの異なるプロセス、または相互に排他的なセマフォなどの同じプロセスにある可能性がありますが、ペアにする必要があります
- 相互に排他的なセマフォの場合、シグナルの前に待機する必要があり、リソースセマフォが最初にシグナルになる場合があります
2.15.2生産者/消費者問題の例
例1
状況の説明
- テーブルの上にプレートがあり、最大でN(N> 0)個の果物を置くことができます(リソーススペースN)
- お父さんはランダムにリンゴやオレンジを皿に置きます(プロデューサー)
- 息子はオレンジだけを食べ、娘はリンゴだけを食べる(2人の消費者)
- 食べたい果物がない場合は、食べないでください(消費者は自分のリソースのセマフォがある場合にそれを消費できます)
- プレートがいっぱいになるとお父さんは果物を入れません(スペース信号が制限されています)
- 一度に出し入れできる果物は1つだけで、プレートを同時に使用することはできません(重要な領域の相互排他的使用)
セマフォメカニズムを使用して、父、息子、娘の間の同期および相互排除アクティビティを実現し、定義されたセマフォの意味を説明します。擬似コードの説明が必要です。
分析
- プロデューサーは、サイズNのクリティカルセクションを共有して、2つのコンシューマー用に2つの異なるリソースを生成します
- プレートはクリティカルセクションであり、ミューテックスセマフォが必要です
- オレンジの生産と消費により、お父さんと息子は同期しています。最初に生産し、次に消費します。
- リンゴの生産と消費のために、父と娘は同期しています:最初に生産、次に消費
- お父さん、息子、娘はクリティカルセクションを共有し、スペースセマフォを空にする必要があります
- 信号:
- 空:プレートが空かどうか
- オレンジ:リソースがあるかどうかオレンジ
- アップル:リソースアップルはありますか
- ミューテックス:ミューテックスセマフォ
擬似コードの実装
semaphore mutex = 1; //盘子操作互斥信号量
semaphore apple = 0, orange = 0; //苹果、桔子放入、取出的资源信号量
semaphore empty = N; //盘子中可放入的水果数目
P1()
{
while (true) {
result= prepare _fruit(); //准备水果,result为水果类型
P(empty); //盘子中可放入的水果数目减1
P(mutex); //互斥访问盘子
put a fruit on the plate; //将一个水果放入盘子
V(mutex); //恢复访问盘子
if (result == apple) //准备的水果为苹果
V(apple); //允许女儿取苹果
else //准备的水果为桔子
V(orange); //允许儿子取桔子
}
}
son() {
while (true) {
P(orange); //判断是否可取桔子
P(mutex); //互斥访问盘子
get an orage from plate(); //取桔子
V(mutex); //恢复访问盘子
V(empty); //盘子中可放入的水果数目加1
}
}
daughter() {
while (true) {
P(apple); //判断是否可取苹果
P(mutex); //互斥访问盘子
get an apple from plate(); //取苹果
V(mutex); //恢复访问盘子
V(empty); //盘子中可放入的水果数目加1
}
}
例2
状況の説明
- テーブルの上に皿があり、果物は1つしか置けません(リソーススペース1)
- お父さんはリンゴを皿に置き、お母さんはオレンジを皿に置きます(2人の生産者)
- 息子はオレンジだけを食べ、娘はリンゴだけを食べる(2人の消費者)
- 食べたい果物がない場合は、食べないでください(消費者は自分のリソースのセマフォがある場合にそれを消費できます)
- 皿が空のときだけ、父または母は果物を置くことができます(スペース信号は限られています)
- 一度に出し入れできる果物は1つだけで、プレートを同時に使用することはできません(重要な領域の相互排他的使用)
セマフォメカニズムを使用して、父、母、息子、娘の間の同期および相互排除アクティビティを実現し、定義されたセマフォの意味を説明します。擬似コードの説明が必要です。
分析
- 2つのプロデューサーが2つのコンシューマー用に2つの異なるリソースを生成し、サイズ1のクリティカルセクションを共有します
- プレートは重要な領域であり、リソースセマフォプレートが必要です
- リンゴの生産と消費のために、父と娘は同期しています:最初に生産、次に消費
- オレンジの生産と消費のために母と息子は同期しています:最初に生産、次に消費
- 信号:
- プレート:プレートが空かどうか
- オレンジ:リソースがあるかどうかオレンジ
- アップル:リソースアップルはありますか
#####相互に排他的なセマフォ
が必要ないのに、なぜ必要ないのか
- 例1では、スペースは複数のリソースを保持できます。スペースが5であるとすると、既存のリソースが3つある場合、プロデューサーとコンシューマーは同時にクリティカルエリアにアクセスできます。一方は新しいリソースを配置し、もう一方は古いリソースをフェッチするには、スペースと相互排除の2つのセマフォが必要です
- 2番目の例では、リソースが0の場合、プロデューサーのみがクリティカルセクションにアクセスでき、リソースが1の場合、コンシューマーのみがクリティカルセクションにアクセスできます。したがって、プロデューサーがクリティカルセクションに入ると、リソースセマフォ+ +作成されていない、コンシューマー相互排除が入力できないためではなく、取得するリソースがないためです。プロデューサーがクリティカルセクションを出るときにのみ、新しく生成されたリソースをフェッチするためにクリティカルセクションへの入力を要求します。消費者がクリティカルセクションに入り、生産者がクリティカルセクションに入らない場合も同様です。クリティカルセクション
- したがって、相互排除はありません
擬似コードの実装
semaphore plate = 1; //是否允许向盘子放入水果
semaphore apple = 0, orange = 0; //盘子中是否有苹果、桔子
dad() {
while (true) {
prepare an apple;
P(plate); //互斥向盘子放水果
put an apple on the plate; //将苹果放入盘中
V(apple); //允许取苹果
}
}
mom() {
while (true) {
prepare an orange;
P(plate); //互斥向盘子放水果
put an orange on the plate; //将桔子放入盘中
V(orange); //允许取桔子
}
}
son()
{
while (true) {
P(orange); //互斥取水果
get an orange from the plate; //从盘中取出桔子
V(plate); //允许向盘中放入水果
}
}
daughter()
{
while (true) {
P(apple); //互斥取水果
get an apple from the plate; //从盘中取出苹果
V(plate); //允许向盘中放入水果
}
}
例3
状況の説明
- テーブルの上に最大2つの果物が入ったお皿があります(リソーススペース2)
- お父さんはリンゴを皿に置き、お母さんはオレンジを皿に置きます(2人の生産者)
- 娘は果物を食べる責任があります(消費者)
- 娘は、プレートにリンゴとオレンジが同時にある場合にのみ果物を取り出します(消費者はリソース信号があるときに消費できます)
- 皿が空のときだけ、父または母は果物を置くことができます(スペース信号は限られています)
- 一度に出し入れできる果物は1つだけで、プレートを同時に使用することはできません(重要な領域の相互排他的使用)
セマフォメカニズムは、父、母、娘の間の同期と相互排除活動を実現し、定義されたセマフォの意味を説明するために使用されます。擬似コードの説明が必要です。
分析
- 2つの異なるリソースを生成する2つのプロデューサーは、サイズ2のクリティカルセクションを共有します
- リンゴの生産と消費のために、父と娘は同期しています:最初に生産、次に消費
- オレンジの生産と消費のために母と息子は同期しています:最初に生産、次に消費
- プレートをリンゴに入れることができるかどうかを判断する必要があります:apple_empty
- プレートにオレンジを入れることができるかどうかを判断する必要があります:orange_empty
- 信号:
- apple_empty:リンゴを入れることができるかどうか
- orange_empty:オレンジを入れることができるかどうか
- オレンジ:リソースがあるかどうかオレンジ
- アップル:リソースアップルはありますか
#####相互に排他的なセマフォ
が必要ないのに、なぜ必要ないのか
- 例1では、スペースは複数のリソースを保持できます。スペースが5であるとすると、3つのリソースがある場合、プロデューサーとコンシューマーは同時にクリティカルエリアにアクセスできます。例2では、リソースが0の場合、プロデューサーはクリティカルエリアにアクセスできます。エリア、リソースが1つある場合、コンシューマーのみがクリティカルエリアにアクセスできます。したがって、プロデューサーがクリティカルエリアに入り、リソースセマフォ++が作成されていない場合、コンシューマーはアクセスできなくなりません。相互排除の、しかし取るリソースがないので。プロデューサーが重要なセクションを出た後にのみ、彼は新しく生産されたリソースをフェッチするために重要なセクションに入ることを要求します
- 例3では、1つのスペースのように見えますが、サイズ2のスペースにはリンゴとオレンジを1つしか入れることができず、2つの同じ果物を入れることはできないため、実際にはサイズ1の2つの別々のスペースになります。 1種類の果物しか入れることができず、2つのプレートの果物を同じにすることはできません。例2を参照してください。この状況は、相互に排他的である必要はありません。
擬似コードの実装
semaphore apple = 0, orange = 0; //盘子中是否有苹果、桔子
semaphore empty_apple = 1, empty_orange = 1; //盘子是否可放入苹果、桔子
dad(){
while (true) {
prepare an apple;
P(empty_apple); //盘子中是否可放入苹果
put an apple on the plate; //将一个苹果放入盘子
V(apple); //允许女儿取苹果
}
}
mom(){
while (true) {
prepare an orange;
P(empty_orange); //盘子中是否可放入桔子
put an orange on the plate; //将一个桔子放入盘子
V(orange); //允许女儿取桔子
}
}
daughter() {
while (true) {
P(apple); //盘子中是否有苹果
P(orange); //盘子中是否有桔子
get an apple and an orange from plate(); //取水果
V(empty_apple); //盘子中可以放入苹果
V(empty_orange); //盘子中可以放入桔子
}
}
例4
状況の説明
- 絵を描くのは娘(プロデューサー)
- 父と母は感謝の責任を負います(2人の消費者)
- 娘がホワイトボードに絵を描き終えたら、新しい絵を作成する前に、父と母に感謝してもらいます
- プロデューサープロセスと2つのコンシューマープロセスはサイズ1のバッファーを共有します。バッファーが空の場合にのみ、プロデューサープロセスがデータを入力し、バッファーにデータがある場合にのみ、コンシューマーがデータを読み取ります。 。両方のコンシューマーがデータを読み取った後、プロデューサーは元のデータを削除して、次のデータの生成を続行できます。
セマフォメカニズムは、父、母、娘の間の同期と相互排除活動を実現し、定義されたセマフォの意味を説明するために使用されます。擬似コードの説明が必要です。
分析
- 1人のプロデューサーと2人の消費者、そして1枚の絵を2人に別々に見せるべきです
- 生産者は毎回異なる消費者のために2つのデータを作成する必要があることがわかります
- 両方のデータが消費された後にのみ、生産を継続できます
- 感謝したことがありますか?スペースリソースセマフォempty_dadを設定します
- お父さんはそれを感謝できますか、製品リソースセマフォfull_dadを設定します
- 感謝したことがありますか?スペースリソースセマフォempty_momを設定します
- お母さんはそれを楽しむことができます、製品リソースセマフォfull_momを設定します
- 信号:
- empty_dad:お父さんは今までに感謝したことがあります
- empty_mom:母親はこれまでに感謝したことがありますか
- full_dad:お父さんは感謝できますか
- full_mom:お母さんは楽しむことができます
擬似コードの実装
semaphore empty_dad = 1, empty_mom = 1; //爸爸、妈妈是否已看过女画的新画
semaphore full_dad = 0, full_mom = 0; //是否存在可供爸爸、妈妈看的新画
daughter(){
while (true) {
P(empty_dad); //爸爸是否看过
P(empty_mom); //妈妈是否看过
draw a new picture on the whiteboard; //画一幅新画
V(full_dad); //爸爸可以看了
V(full_mom); //妈妈可以看了
}
}
dad() {
while (true) {
P(full_dad); //白板上是否存在没有看过的画
enjoy the picture on the whiteboard; //看画
V(empty_dad); //爸爸已看过新画
}
}
mom() {
while (true) {
P(full_mom); //白板上是否存在没有看过的画
enjoy the picture on the whiteboard; //看画
V(empty_mom); //妈妈已看过新画
}
}