2.16リーダーとライターの問題
抽象解釈
- 複数のプロセスが共有データ領域にアクセスします
- リーダー(読み取りプロセス)はデータの読み取りのみが可能であり、ライター(書き込みプロセス)はデータの書き込みのみが可能です。
- データベース、ファイル、メモリ、レジスタなどのデータ領域のアクセスモデルに適しています。
- たとえば、12306チケットシステムでは、大量のユーザーと大量のデータがあるため、複数のプロセスが同じデータを同時にクエリ(読み取り)または変更(書き込み)することは避けられません。
2.16.1リーダーとライターの問題に関する3つの制約
- 読者は相互に排他的ではありません(あなたとあなたのルームメイトは元旦の午前7時に高速鉄道の情報を同時に見ることができます)
- ライターは相互に排他的である必要があります(元旦の朝7時にG1234の6Dポジションの購入を同時に申請することはできません)。
- リーダーとライターも相互に排他的です(G1234の6Dシートを購入している場合、ルームメイトはそのポジションのチケット情報を読み取ることができません)
2.16.2リーダーライターの問題とプロデューサー消費者の問題
生成/消去の問題のように厳密に相互に排他的であることはできません。ライターはデータの正確性を保証できますが、同時読み取りの機能を実現することはできません。
- 生産者/消費者問題:消費後にデータが失われる;リーダー/ライター問題:データが複数回読み取られる可能性がある
- 生産者/消費者問題:消費者は相互に排他的;リーダー/ライターの問題:リーダーは同時に読むことができる
2.16.3リーダーとライターの問題に対する3つの解決策
戦略リーダーファースト
- 読者が読んでいる場合、後続の読者は一緒に読むためにクリティカルセクションに入ることができます
- クリティカルセクションのすべてのリーダーが終了するまで待ってから、次のライターの番になります
- 作家を追い越し、作家を飢えさせる現象があります
可変設定
- wsem:相互に排他的なセマフォ
- readcount:同時に読んだリーダーを数えます
- x:読み取りカウントの変更をロックする
偽のコード
int readcount=0;
semaphore x = 1, wsem=1;
void reader() {
while (1) {
P(x);
readcount++;
Ⅰ if (readcount==1) P(wsem); //第一个读者会执行此if语句,随后的会跳过P(wsem)直接进入临界区
Ⅱ V(x);
READ;
P(x);
readcount--;
Ⅲ if (readcount==0) V(wsem);//最后退出的读者执行此语句,释放临界区权限
Ⅳ V(x);
}
}
void writer() {
while (1) {
P(wsem);
WRITE;
V(wsem);
}
}
読者第一の考慮事項
- IとIIの文は交換可能ですか?
回答:いいえ、readcountの判断はロックされている必要があります。そうでない場合、読み取りと書き込みの相互排除はありません。この時点でライターがクリティカルセクションにあると仮定すると、最初のリーダーの到着後のreadcount ++がブロックされます。 P(wsem)、および2番目のリーダー到着後、count ++を直接変更して、P(wsem)のクリティカルセクションに直接入ることができ、読み取りと書き込みは相互に排他的ではありません。この時点で失われる条件は、リーダーが最初にクリティカル領域に入るとき、それが入った後のリーダーがカウントを変更できることです。 - Ⅲ文とⅣ文を入れ替えることはできますか?
回答:いいえ。交換後、最後のプロセスが終了したときの別のリーダープロセスの状況を考慮してください。交換後、readcount = 0、ifが判断されなかった場合でも、リーダーはクリティカルセクションに入ります。判断後、クリティカルセクションの権限が解放され、ライターもクリティカルセクションに入ります。現時点では、読み取りと書き込みは相互に排他的ではありません。この時点で失われる条件は次のとおりです。最後のリーダーがクリティカルセクションを終了するとき、カウントは終了後にのみ変更できます。 - 次の一連のプロセスを検討してください(プロセスの到着の順序として、右から左への順序であると想定します)。次の状況のうち、ライターが
不足している可能性があるのはどれ
ですか
。1.RRR2.WWW
3.RW 4.RRW
5.RRWR
6.WWR
7. WRRW
回答:5。RRWRでは、Rが最初にクリティカルセクションに到着し、後続のリーダープロセスは待機中にP(wsem)をクリティカルセクションに直接渡します。つまり、Wを渡します。飢えさせる作家
戦略2:公平性を第一に
- 読者が読んでいる場合、次の作家の前の読者はクリティカルセクションに入り、一緒に読むことができます
- 書き込みプロセス中に、他の着信プロセスが順番に処理されます
- 作家を追い越さないという現象は、作家を飢えさせることはありません
可変設定
- wsem:相互に排他的なセマフォ
- readcount:同時に読んだリーダーを数えます
- x:読み取りカウントの変更をロックする
- wrsem:相互に排他的なセマフォ、リーダー、ライターがここにキューに入れられます。有用性はリーダーの優先度に基づいており、リーダーはライターを通過できません。
偽のコード
int readcount=0, semaphore x=l, wrsem=1, wsem=l;
void reader() {
while (true) {
P(wrsem);
P(x);
readercount++;
if (readercount == 1)
P(wsem);
V(x);
V(wrsem);
READ;
P(x);
readercount--;
if (readercount == 0)
V(wsem);
V(x);
}
}
void writer() {
while (true) {
P(wrsem);
P(wsem);
WRITE;
V(wsem);
V(wrsem);
}
}
最初に読者と比較
リーダー優先度では、wsemは最初のリーダーのみをブロックし、後続のリーダーは影響を受けません。到着順に確実に処理するために、wrsemはフェアプライオリティモードで設定され、リーダー/ライターは到着順にwrsemにキューイングします。
最初に3人の作家を戦略する
- ライターが書き込みを宣言すると、リーダーはクリティカルセクションに入ることができなくなります。
- 同時実行性の低下
- リーダーをオーバーライドする現象があり、リーダーが飢えます
可変設定
- rsem:相互に排他的なセマフォ。少なくとも1人のライターがデータの書き込みを申請すると、相互に排他的な新しいリーダーが入力してデータを読み取ります。
- 最初のライターはrsemの影響を受けます。最初のライターが存在すると、後続のライターはrsemの影響を受けません。しかし、読者はrsemに列を作る必要があります
- writecount:rsemによるライターの制御を制御するために使用されます
- y:書き込みカウントの変更をロックします
偽のコード
int readcount = 0, writecount = 0;
semaphore x=l, y= 1, wsem=1, rsem=l;
void reader( ) {
while (1) {
P(rsem);
P(x);
readcount++;
if (readcount ==1) P(wsem);
V(x);
V(rsem);
READ;
P(x);
readcount--;
if (readcount ==0) V(wsem);
V(x);
}
}
void writer( ) {
while (1) {
P(y);
writecount++;
if (writecount ==1) P(rsem);
V(y);
P(wsem);
WRITE;
V(wsem);
P(y);
writecount--;
if (writecount==0) V(rsem);
V(y);
}
}
最初の公平性と比較して
公平性の優先順位では、リーダーとライターの両方がwrsemによって制限されますが、ライターの優先順位では、if(writecount == 1)P(rsem)ステートメントが追加されるため、ライターが到着すると、ライターが到着する前にクリティカル領域に入ります。リーダー、ただしWRRRRの場合、ライターは優先されません
戦略4ライターは改善を優先する
- WRRRRでWを優先できないという問題を解決するために
可変設定
- ライターファースト変数
- zセマフォを増やすことは、ライターにのみ役立ち、リーダーはzでキューに入れられ、1つのリーダーのみがrsemでキューに入れられます。
偽のコード
int readcount=0,writecount=0;
semaphore x=l, y= 1,z=1,wsem=1,rsem=l;
void reader( ) {
while (1) {
P(z);
P(rsem);
P(x);
readcount++;
if (readcount ==1) P(wsem);
V(x);
V(rsem);
V(z);
READ;
P(x);
readcount--;
if (readcount ==0) V(wsem);
V(x);
}
}
void writer( ) {
while (1) {
P(y);
writecount++;
if (writecount ==1) P(rsem);
V(y);
P(wsem);
WRITE;
V(wsem);
P(y);
writecount--;
if (writecount==0) V(rsem);
V(y);
}
}
作家は改善方法を優先する
- zセマフォはどのような役割を果たしますか?
- rsemで読み取りプロセスの長いキューを作成することは許可されていません。そうしないと、書き込みプロセスはこのキューをスキップできません。
- 1つの読み取りプロセスがrsemでキューに入れられ、他の読み取りプロセスがセマフォzでキューに入れられるようにします。
- P(z)とP(rsem)はポジションを交換できますか?
いいえ、そうでない場合、P(z)はその制限効果を失います
2.16.4リーダーとライターの質問の例
例1
状況の説明
- 東西方向の単板橋は1人でしか渡れません。
- 東から西へ橋を渡るのを待っている人がいます
PとVの操作を使用して、東端と西端での横断歩道の問題を実現してください
分析
- 単純なライターの相互排除問題
- 複数のライターがデータを共有
- 歩行者は作家であり、橋はデータです
- 信号
- s:相互に排他的なセマフォ
偽のコード
semaphore s = 1; //互斥信号量
void east_west( )
{
while (true) {
P(s); //互斥其他人过桥
walk across the bridge from east to west; //行人从东向西过桥
V(s); //允许其他人过桥
}
}
void west_east( )
{
while (true) {
P(s); //互斥其他人过桥
walk across the bridge from west to east; //行人从西向东过桥
V(s); //允许其他人过桥
}
}
例2
状況の説明
- 東西方向の単板橋は1人でしか渡れません。
- 東から西へ橋を渡るのを待っている人がいます
- 同じ方向の歩行者は継続的に橋を渡ることができ、反対側の歩行者は待たなければなりません
PとVの操作を使用して、東端と西端での横断歩道の問題を実現してください
分析
- 読者の優先質問
- 歩行者は最初に読者のために、もう一方は作家のために橋の上を歩きます。橋はデータです
- 信号
- x:相互に排他的なセマフォ、相互に排他的なリーダーライター
- countR:読者の数(同時に橋の上の歩行者の数)を数えます
- mutexR:変数countRをロックします
偽のコード
int countA=0, countB=0;
semaphore x=1, mutexA=1, mutexB=1;
void east_west() {
while (1) {
P(mutexA);
countA++;
if (countA==1) P(x);
V(mutexA);
walk across the bridge from east to west;
P(mutexA);
countA--;
if (countA==0) V(x);
V(mutexA);
}
}
void west_east() {
while (1) {
P(mutexB);
countB++;
if (countB==1) P(x);
V(mutexB);
walk across the bridge from west to east;
P(mutexB);
countB--;
if (countB==0) V(x);
V(mutexB);
}
}
例3
状況の説明
- 東西方向の単板橋は滞在できません
- 東から西へ橋を渡るのを待っている人がいます
- 同じ方向の歩行者は継続的に橋を渡ることができ、反対側の歩行者は待たなければなりません
- 橋は4人までサポートできます
PとVの操作を使用して、東端と西端での横断歩道の問題を実現してください
分析
- 読者の優先質問
- 歩行者は最初に読者のために、もう一方は作家のために橋の上を歩きます。橋はデータです
- 例2との違いは、橋が耐力限界に達しない限り、橋を1つずつ横断する必要がないことです。ここでの耐力限界は、臨界のサイズです。ゾーン。
- 信号
- x:相互に排他的なセマフォ、相互に排他的なリーダーライター
- countR:読者の数(同時に橋の上の歩行者の数)を数えます
- mutexR:変数countRをロックします
- カウント:一枚板橋の歩行者数
偽のコード
int countA=0, countB=0;
semaphore x=1, muteA=1, mutexB=1,count=4;
void east_west() {
while (1) {
P(mutexA);
countA++;
if (countA==1) P(x);
V(mutexA);
P(count);
walk across the bridge from east to west;
V(count);
P(mutexA);
countA--;
if (countA==0) V(x);
V(mutexA);
}
}
void west_east() {
while (1) {
P(mutexB);
countB++;
if (countB==1) P(x);
V(mutexB);
P(count);
walk across the bridge from west to east;
V(count);
P(mutexB);
countB--;
if (countB==0) V(x);
V(mutexB);
}
}