【オペレーティングシステム】第2章--プロセスの説明と制御--深く解釈(2)


詳しく説明する前に、対応するメモの理解→【オペレーティングシステム】第2章–プロセスの説明と制御–メモと理解(2)

文書ディレクトリ

  • 第2章--プロセスの説明と制御--深く解釈(2)
  • の3つの古典的なケースの同期コード
  • 生産者-消費者
  • 読者-書き手
  • 哲学者食事
  • 3 3つのケース
  • を理解する
  • 生産者-消費者モデルが体現できる設計メリット
  • 読者-ライターモデルの生活における応用
  • 生産者と消費者の問題では、producer()とconsumer()にはそれぞれ2つのwait()操作と2つのsignal()操作があり、隣接する操作の順序を変えることができ、変更はどのような影響を及ぼすのでしょうか.
  • 生産者と消費者の問題では、バッファが満たされている場合、交換生産者のwait()操作、および交換消費者のwait()操作は、どのような影響を及ぼすのでしょうか.
  • 同期と反発の違いと関連
  • 第二章–プロセスの説明と制御–詳細と説明(2)


    3つの古典的なケースの同期コード


    生産者-消費者
  • 単一生産者-単一消費者-単一バッファ
  • //  
    void *producer(void *p) {
        while(1) {
            sem_wait(&space);
            printf("Put a product
    "); sem_post(&prod); } return NULL; } void *consumer(void *p) { while(1) { sem_wait(&prod); printf("Get a product
    "); sem_post(&space); } return NULL; } // #include #include #include #include #include sem_t space,prod; void *producer(void *p) { while(1) { sem_wait(&space); printf("Put a product
    "); sem_post(&prod); } return NULL; } void *consumer(void *p) { while(1) { sem_wait(&prod); printf("Get a product
    "); sem_post(&space); } return NULL; } int main(void) { sem_init(&space,0,1); sem_init(&prod,0,0); pthread_t tid[2]; pthread_create(&tid[0],NULL,producer,NULL); pthread_create(&tid[1],NULL,consumer,NULL); sem_destroy(&space); sem_destroy(&prod); pthread_join(tid[0],NULL); return 0; }
  • 単一生産者-単一消費者-マルチバッファ
  • //  
    void *producer(void *p) {
        while(1) {
            sem_wait(&space);
            printf("Put a product into Buffer[%d]
    ",in); in = (in+1)%N; sem_post(&prod); } return NULL; } void *consumer(void *p) { while(1) { sem_wait(&prod); printf("Get a product from Buffer[%d]
    ",out); out = (out+1)%N; sem_post(&space); } return NULL; } // #include #include #include #include #include #define N 10 sem_t space,prod; int BUffer[N]; int in=0,out=0; void *producer(void *p) { while(1) { sem_wait(&space); printf("Put a product into Buffer[%d]
    ",in); in = (in+1)%N; sem_post(&prod); } return NULL; } void *consumer(void *p) { while(1) { sem_wait(&prod); printf("Get a product from Buffer[%d]
    ",out); out = (out+1)%N; sem_post(&space); } return NULL; } int main(void) { sem_init(&space,0,N); sem_init(&prod,0,0); pthread_t tid[2]; pthread_create(&tid[0],NULL,producer,NULL); pthread_create(&tid[1],NULL,consumer,NULL); sem_destroy(&space); sem_destroy(&prod); pthread_join(tid[0],NULL); return 0; }
  • マルチプロダクション-マルチコンシューマ
  • //  
    void *producer(void *p) {
        while(1) {
            sem_wait(&space);
            sem_wait(&buf);
            printf("Put a product into Buffer[%d]
    ",in); in = (in+1)%N; sem_post(&prod); sem_post(&buf); } return NULL; } void *consumer(void *p) { while(1) { sem_wait(&prod); sem_wait(&buf); printf("Get a product from Buffer[%d]
    ",out); out = (out+1)%N; sem_post(&space); sem_post(&buf); } return NULL; } // #include #include #include #include #include #define M 8 #define N 10 sem_t space,prod,buf; int Buffer[N]; int in = 0, out = 0; void *producer(void *p) { while(1) { sem_wait(&space); sem_wait(&buf); printf("Put a product into Buffer[%d]
    ",in); in = (in+1)%N; sem_post(&prod); sem_post(&buf); } return NULL; } void *consumer(void *p) { while(1) { sem_wait(&prod); sem_wait(&buf); printf("Get a product from Buffer[%d]
    ",out); out = (out+1)%N; sem_post(&space); sem_post(&buf); } return NULL; } int main(void) { sem_init(&space,0,N); sem_init(&prod,0,0); sem_init(&buf,0,1); pthread_t tid[M],tid2[M]; for(int i = 0; i < M; i ++) { pthread_create(&tid[i],NULL,producer,NULL); } for(int i = 0; i < M; i ++) { pthread_create(&tid2[i],NULL,consumer,NULL); } sem_destroy(&space); sem_destroy(&prod); sem_destroy(&buf); pthread_join(tid[0],NULL); return 0; }

    読者-ライター
  • 読者-ライター-読者優先
  • //  
    void *reader(void *p) {
        sem_wait(&srcount);
        readcount++;
        if(readcount == 1) {
            sem_wait(&sdata);
        }
        sem_post(&srcount);
        printf("Reading..
    "); sem_wait(&srcount); readcount--; if(readcount == 0) { sem_post(&sdata); } sem_post(&srcount); return NULL; } void *writer(void *p) { sem_wait(&sdata); printf("Writing..
    "); sem_post(&sdata); return NULL; } // #include #include #include #include #include #define M 10 sem_t sdata,srcount; int readcount = 0; void *reader(void *p) { sem_wait(&srcount); readcount++; if(readcount == 1) { sem_wait(&sdata); } sem_post(&srcount); printf("Reading..
    "); sem_wait(&srcount); readcount--; if(readcount == 0) { sem_post(&sdata); } sem_post(&srcount); return NULL; } void *writer(void *p) { sem_wait(&sdata); printf("Writing..
    "); sem_post(&sdata); return NULL; } int main(void) { sem_init(&sdata,0,1); sem_init(&srcount,0,1); pthread_t tid[M],tid2[M]; for(int i = 0; i < M; i ++) { pthread_create(&tid[i],NULL,writer,NULL); } for(int i = 0; i < M; i ++) { pthread_create(&tid2[i],NULL,reader,NULL); } sem_destroy(&sdata); sem_destroy(&srcount); pthread_join(tid[0],NULL); return 0; }
  • 読者-ライター-ライター優先
  • //  
    void *reader(void *p) {
        sem_wait(&sdata);
        sem_wait(&srcount);
        sem_post(&sdata);
        printf("Reading..
    "); sem_post(&srcount); return NULL; } void *writer(void *p) { sem_wait(&sdata); for(int i = 0; i < N; i++) { sem_wait(&srcount); } printf("Writing..
    "); for(int i = 0; i < N; i++) { sem_post(&srcount); } sem_post(&sdata); return NULL; } // #include #include #include #include #include #define M 10 sem_t sdata,srcount; int readcount = 0; void *reader(void *p) { sem_wait(&srcount); readcount++; if(readcount == 1) { sem_wait(&sdata); } sem_post(&srcount); printf("Reading..
    "); sem_wait(&srcount); readcount--; if(readcount == 0) { sem_post(&sdata); } sem_post(&srcount); return NULL; } void *writer(void *p) { sem_wait(&sdata); printf("Writing..
    "); sem_post(&sdata); return NULL; } int main(void) { sem_init(&sdata,0,1); sem_init(&srcount,0,1); pthread_t tid[M],tid2[M]; for(int i = 0; i < M; i ++) { pthread_create(&tid[i],NULL,writer,NULL); } for(int i = 0; i < M; i ++) { pthread_create(&tid2[i],NULL,reader,NULL); } sem_destroy(&sdata); sem_destroy(&srcount); pthread_join(tid[0],NULL); return 0; }

    哲学者の食事
  • 基本案
  • #include
    #include
    #include
    sem_t sfork[5];
    void *philosopher(void*p) {
        int id=(int)p;
        while(1){
            printf("Thinking...
    "); sem_wait(&sfork[id]); sem_wait(&sfork[(id+1)%5]); printf("Eating...
    "); sem_post(&sfork[id]); sem_post(&sfork[(id+1)%5]); } return NULL; } int main() { for(int i=0;i<5;i++) sem_init(&sfork[i],0,1); pthread_t tid[5]]; for(int i=0;i<5;i++) pthread_create(&tid[i],NULL,philosopher,(void*)i); for(int i=0;i<5;i++) sem_destroy(&sfork); pthread_join(tid[0],NULL); }
  • ソリューション1
  • #include
    #include
    #include
    sem_t sfork[5];
    void *philosopher(void*p) {
        int id=(int)p;
        while(1){
            printf("Thinking...
    "); if(id%2==0){ sem_wait(&sfork[id]); sem_wait(&sfork[(id+1)%5]); } else{ sem_wait(&sfork[(id+1)%5]); sem_wait(&sfork[id]); } printf("Eating...
    "); sem_post(&sfork[id]); sem_post(&sfork[(id+1)%5]); } return NULL; } int main() { for(int i=0;i<5;i++) sem_init(&sfork[i],0,1); pthread_t tid[5]]; for(inti=0;i<5;i++) pthread_create(&tid[i],NULL,philosopher,(void*)i); for(inti=0;i<5;i++) sem_destroy(&sfork); pthread_join(tid[0],NULL); }
  • ソリューション2
  • #include
    #include
    #include
    sem_t sfork[5];
    void *philosopher(void*p) {
        int id=(int)p;
        while(1){
            printf("Thinking...
    "); if(id%==4){ sem_wait(&sfork[0]); sem_wait(&sfork[4]); } else{ sem_wait(&sfork[id]); sem_wait(&sfork[id+1]); } printf("Eating...
    "); sem_post(&sfork[id]); sem_post(&sfork[(id+1)%5]); } return NULL; } int main() { for(int i=0;i<5;i++) sem_init(&sfork[i],0,1); pthread_ttid[5]]; for(int i=0;i<5;i++) pthread_create(&tid[i],NULL,philosopher,(void*)i); for(int i=0;i<5;i++) sem_destroy(&sfork); pthread_join(tid[0],NULL); }

    3つのケースを理解する


    生産者-消費者モデルが体現できる設計メリット
  • デカップリング:概念的に言えば、結合は2つ以上のシステムまたは2つの運動形態間が相互作用によって互いに影響し合い、結合する現象を指し、デカップリングは実際には数学的方法で2つの運動を分解して問題を処理する.生産者-消費者モデルはどのように解結合の思想を体現しているのだろうか.簡単な例を挙げると、私たちは食事の味を変えたいと思っています.出前を注文したいと思っています.いろいろな出前プラットフォームがない前に、街には出前のお兄さんの姿があちこちにいません.私たちは出前を注文したいと思っています.電話で直接店に行って食事を注文することが多いです.注文の電話を受けた社長も、電話を受けたり、料理を作ったり、客に食事を送ったりすることが多い.では、私たちはこの时のボスがあまりにも容易ではないことに気づきます.まず、自分で野菜を洗って料理をしなければなりません.料理を作った後、自分で包装しなければなりません.それから、自転車や電気自動車に乗って自分で食事を届けなければなりません.また、町全体の道をよく知っていて、迅速で正確であることを保証しなければなりません.一人の社長がすべてのことを請け負うのは本当に大変です.それに、この注文の出前時間が長いと、次の注文の時間に直接影響します.慌てて料理をしている間に自分を傷つけてしまったら、この日の料理はできないかもしれません.料理と食事の2つのものは互いに結びつき、影響し合い、すべて結合している.しかし、外食のお兄さんがいれば違います.ボスは料理を作ることに専念すればいいです.食事の問題は外食のお兄さんに任せておけばいいです.職能がはっきりしていて、効率が自然に高くなります.ここでは、ボスを生産者として、お兄さんを消費者として、この結合の問題を解決することができます.
  • 消費者と生産者の能力をバランスさせる:同じように外食の例を挙げると、ボスが料理を作るのが速いが、お兄さんが食事を送るのにかかる時間が長いと、私たちが外食を手に入れるのに長い時間がかかり、最終的に待っているのはボスが本当に出したい料理の様子ではないので、私たちはこの料理に悪い感じを生んだかもしれません.同じように、社長が料理が遅い場合、出前のお兄さんがずっと店で待っているなど、この食事を注文したお客様の食事時間に影響を与えるのは言うまでもなく、他の注文も遅れてしまうので、同じ問題です.生産者-消費者モデルはすでに彼のより明確な分離しかできないため、解決しても迅速に対症して薬を処方することができる.第1種の消費者の消費(出前の兄)の速度が生産者の生産(ボス)の生産能力に追いつかないという問題に対して、私たちは消費者に注目するだけで、出前の兄をもっと増派することができて、みんなは一人で自分の最もよく知っている区域を管理して、迅速で、正確率はまだ高いです;第2の生産者(ボス)の生産能力が消費者(出前の兄)の速度に追いつかない問題に対して、私たちは生産者の生産能力を高めることに注目するだけで、コックを多く雇って、支店を多く開くと生産能力の問題をよく解決することができます.これにより、生産者と消費者の間の生産能力の不均衡の問題を解決することができる.

  • 読者-ライターモデルの生活における応用
  • 読者-ライターモデルは実は3つの重要な点に従う:読み書き相互反発、書き書き相互反発、読み書き相互反発;
  • とても简単な例を挙げて、ふだんの授业の学习の中で、授业をしている先生は往々にしてコンピュータとプロジェクターを使って授业を补助して、スクリーンの上の内容に投げて、教室の中の学友はすべて同时に见て、同时に新しい知识を受け入れることができて、ここで読みますか?反発しません、私は私を読んで、あなたはあなたを読んで、私达は内容に対してすべて変えないで、だから反発する问题はありません;反転教室を行う时、多くの学友はすべて自分のPPTを教室のコンピュータにコピーして、自分の番になった时、自分のPPTを说明して、この时间の中で、コンピュータの使用権はすべての授业中の学友に渡して、2つの同学は同时にコンピュータを操作して、1対のキーボードのマウスだけあって、2人が同时に操作することを许さなくて、これは読者-书き手の模型の中の书き込みと书き込みの反発に対応します;PPTをデモンストレーションする过程の中で、突然1か所の间违いがあることを発见して、その场で少し修正する必要があって、もちろん直接デモンストレーションしているPPTの中で直接修正することはできなくて、先にPPTの编集モードに切り替えて、彼に対して再び编集して保存して、再びPPTを开いてデモンストレーションを行う时、现れた内容は修正した后の正しい内容で、ここで読み書きの反発を体現しました;

  • 生産者と消費者の問題では,producer()とconsumer()にはそれぞれ2つのwait()操作と2つのsignal()操作があり,隣接する操作の順序を変え,変化がどのような影響を及ぼすか.
  • producer()内:
  • wait(empty)を操作①
  • と記す.
  • wait(mutex)は、操作②
  • と記す.
  • consumer()内:
  • wait(full)を操作③
  • と記す
  • wait(mutex)は操作④
  • と記す
  • producer()内:
  • signal(mutex)を操作⑤
  • と記す.
  • signal(full)を操作⑥
  • と記す
  • consumer()内:
  • signal(mutex)を操作⑦
  • と記す
  • signal(empty)は、操作⑧として記載される.

  • wait():3と④を交換し、プロセスが開始されると、まず1を実行し、wait(empty)を真とし、実行を継続する.そして4を実行し、wait(mutex)を真とし、実行を継続する.次に2を実行し、wait(mutex)を偽とし、生産者プロセスがブロックされる.その後、③wait(full)を偽として実行し、消費者プロセスがブロックされるため、交換できない.
  • signal():交換できますが、オーバーヘッドが発生します.⑤⑥を交換すると、⑥signal(full)は消費可能バッファを待つプロセスを呼び覚まし、consumerでwait(full)操作を真とし、wait(mutex)を偽として実行し続け、ブロックする.しかし5 signal(mutex)は臨界領域への進入を待つプロセスを呼び覚ます.だから交換できますが、オーバーヘッドは相対的に大きいです.

  • 生産者と消費者の問題では,バッファが満たされている場合,生産者のwait()操作を交換し,消費者のwait()操作を交換すると,どのような影響を及ぼすか.
  • この時点でバッファ内に製品が満タンになるとempty=0,full=n.生産者はwait(mutex)を実行してmutexを0にしてwait(empty)を実行し、空きバッファがないため生産者はブロックされる.生産者がブロックされているため、消費者プロセスが消費者プロセスに切り替わると、消費者プロセスはwait(mutex)を実行し、mutexが0であるため、すなわち生産者はまだ臨界資源に対するロックを解放していないため、消費者もブロックされる.これにより、生産者は消費者が空きバッファを解放するのを待っているが、消費者は生産者が臨界領域を解放するのを待っている場合、生産者と消費者は循環して相手に呼び覚まされるのを待っており、「デッドロック」
  • をもたらした.
    同期と反発の違いと関連
  • 相互反発とは、3つの異なるプロセス間のいくつかのプログラム断片を指し、あるプロセスが1つのプログラム断片を実行すると、他のプロセスはそれらのいずれかのプログラム断片を実行することができず、そのプロセスがこのプログラム断片を実行してからしか実行できない.同期とは、異なるプロセスの間を散歩するいくつかのプログラムの断片を指し、それらの実行は厳格に規定されたある前後の順序に従って実行しなければならない.このような前後の順序は完成する特定の任務に依存している.同期はより複雑な反発であり、反発は特殊な同期である.つまり、反発は2つのスレッドの間で同時に実行できません.彼らは互いに反発し、1つのスレッドが実行されるのを待たなければなりません.もう1つは実行できません.同期も同時に実行できません.しかし、彼は何らかの順序で対応するスレッド(反発でもあります)
  • を実行しなければなりません.