コンピュータオペレーティングシステムの基礎(4)-プロセス管理のプロセス同期

前書き

この記事は4番目の記事であるプロセス管理のプロセス同期です。この記事では主にプロセス間同期が必要な理由と、プロセス間同期とスレッド同期の原則を紹介します。

1つは、プロセス間同期が必要な理由です。

プロセス同期は何か、プロセス同期が必要な理由を理解するための2つの例

(1)生産者/消費者問題

問題の説明:製品の生産における生産者プロセスのグループ、および消費者プロセスが消費するため利用可能なこれらの製品、生産者プロセスおよび消費者プロセスは、2つの間でバッファnバッファプール、生産者プロセスを設定し、同時に実行できます生産された製品をバッファーに入れる必要があり、消費者プロセスは消費のためにバッファーから製品を取り出すことができます

生産と消費のプロセス

生産者が製品を生産する場合、緩衝地帯の製品は+1になります。同様に、消費者が緩衝地帯の製品を消費する場合、緩衝地帯の製品は-1になります。そのようなモデルは実際にはありません。問題がある(たとえば、組立ラインで携帯電話を生産する携帯電話工場が倉庫に配置され、消費者が携帯電話を倉庫から取り出して消費する。この生産者-消費者モデルは、マクロから問題がない。視点)
ここに画像の説明を挿入

上記のモデルはマクロの観点からは問題ありませんが、コンピューターのミクロの観点から見ると問題が発生します。
コンピューターでは、このバッファーはキャッシュまたはメインメモリにあります。プロデューサーまたはコンシューマーがその中のデータを操作する場合、次の3つのステップに分けられます。

a。データを取り出し、レジスタレジスタに入れます= count

b。CPUのレジスターのRegister + 1およびregister = register + 1、プロデューサーが製品を完成させたことを示します。

c。レジスタをバッファに戻しますcount = register

これらの3つのステップは、バッファーを操作するために必要な3つのステップです。バッファは倉庫、レジスターは生産者の場所、消費者の場所と考えることができますが、一見問題ないようです。
ここに画像の説明を挿入

プロデューサープログラムまたはコンシューマープログラムだけを見ても大丈夫ですが、2つを同時に実行するとエラーが発生する可能性があります

下の赤い部分は生産者による生産プロセスであり、青い部分は消費者の消費プロセスです

レジスターとカウントを2つの部分の値として(10と仮定)、この時点でプロデューサーの最初のステップが実行されたと仮定します。つまり、register = count、この時点で両方とも10であり、次にプロデューサーの2番目のステップが実行されますステップ、register = register + 1、この時点でレジスタの値は+1、次にregister = 11、この時点でcount = 10であり、プロデューサプログラムとコンシューマプログラムが同時に実行されると仮定すると、3番目のステップが可能です。実行するのはコンシューマーの番です。次に、それがコンシューマーのregister = countの最初のステップであるとすると、この時点コンシューマーのプロセスのレジスターの値は10であり、4番目のステップが実行されます。第4工程を仮定すると、ある消費者の第二段階、実行されるレジスタ=レジスタ-1 この時、消費者のプロセスのレジスタの値となる9、キャッシュ内の値はまだ10次に行います5番目のステップ、および5番目のステップは実行を想定します。コンシューマーへの3番目のステップはcount = registerです。つまり、レジスターの値がバッファーに書き戻されます。このとき、バッファーの値とコンシューマー・レジスターは次のようになります。両方とも9であり、コンシューマーの操作はここで完了します。次に、プロデューサー操作があり、プロデューサーのレジスターをバッファーに書き戻します。今、プロデューサーのレジスターは11に等しくなります。、次に、このステップを実行した後、レジスタをバッファに書き換え、バッファ内の値は11、count = registerになります。実際、この外観には問題があります。最初は、バッファーの値は10で、実行中に+1および-1操作が実行された後、その値は10のままですが、リース後はは11になり、データが間違っていることを示します。エラーの理由は、2つのプロセスが同時に実行されているためです。これらは操作バッファーで交互に実行され、バッファー内のデータに一貫性がなくなります。これは生産者/消費者問題です。

実際の実行の例を見てみましょう。以下は、2つのスレッドを使用してプロデューサーとコンシューマーのプロセスをシミュレートする単純なプログラムです。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <vector>

pthread_ mutex t mutex = PTHREAD MUTEX INITIALIZER;
int num = 0;//全局变量,初始值为0
void *producer(void*){//生产者
      int times = 10000000 ;
      while(times -- ){//生产者将num循环+1很多次,表示生产过程,消费者是循环-1
      //pthread mutex_ lock (&mutex) ;
      num+=1;
      //pthread mutex unlock (&mutex) ;
  }
}

void *comsumer (void* ){//消费者
      int times = 10000000 ;while(times -- ){
      //pthread mutex lock (&mutex) ;
      num  -=  1;
      //pthread mutex unlock (&mutex) ;
  }
}

//在main函数中创建了两个线程来模拟两个进程,一个线程执行producer的逻辑,一个线程执行comsumer的逻辑
int main()
{
	printf("Start a main function.");
	pthread_t thread1,thread1;
	pthread_create(&thread1, NULL, &producer, NULL);
	pthread_create(&thread1, NULL, &comsumer, NULL);
	pthread_join(thread1, NULL);
	pthread_join(thread2, NULL);
	printf("Print in main function: num = %d\n", num);
	retuen 0
}

プロデューサーとコンシューマーのサイクルタイムは同じであるため、実行結果は0になります。実際の実行結果ではありませんか?そうではないことがわかるので、これは生産者と消費者の問題です。上記の例のbufferとnumは重要なリソースです

(2)哲学者の食事の問題

問題の説明:5人の哲学者がいます。彼らのライフスタイルは思考と食事を交互に行うことです。哲学者は円卓を共有し、周りの5つの椅子に座っています。円卓には5つのボウルと5つの箸があります。通常、哲学者は考えるだけです。お腹が空いたときは、2本の箸を近づけようとします。両方の箸を持っているときだけ食べられます。食後は、箸を置いて考え続けます。
ここに画像の説明を挿入

では、なぜこのプロセスにプロセスの同期が必要なのですか?哲学者が食べるとどうなるか想像してみてください。この時点で哲学者がお腹が空いていて、左側の箸と右側の箸を手に取って食べる必要があるとします。このとき、最初のステップは左側の箸を拾い、2番目のステップは右側の箸を拾うことです。この時点で右側の箸が取られていることに気付いた場合、彼は待ちます。右側の箸を離すために。箸を離した後、右側の箸を手に取って食べ始めます。これは哲学者が食べるときに直面するかもしれない問題です。この見方からすると、問題はないようです。
ここに画像の説明を挿入

極端な状況を見て、この5人の哲学者が同時に空腹で、左側を同時に拾うと、右側の箸すべて取られたことがわかります(円卓会議と比較してください)。上の写真をクリック)すると、このとき、5人の哲学者が右側の箸が解放されるのを待ちます。このとき、すべての箸が自分で拾われるので、お互いを待ち、手に入れることができません。箸、そしてどちらも彼の左側の箸を解放しないので、これらの5人の哲学者は餓死するでしょう。これは最も極端な状況です。

上記は哲学者の食事の問題です。今度は箸を資源に、哲学者をプロセスに置き換えます。これはコンピュータプロセスが直面する問題です。箸は重要な資源です。

上記の2つの問題の根本的な原因を要約してください。

  • 問題の根本的な原因は次のとおりです。相互の通信がない
  • 最初の生産者/消費者問題、私たちは生産者が私が生産を完了したことを消費者に通知すると仮定します
  • 2番目の哲学者の食事の問題、哲学者が私の隣の哲学者に私が食べたいと言ったとしたら、問題はありません

結論を導き出す

プロセス間同期が必要ですがプロセス間同期はどのような問題を解決しますか?

1.複数のプロセス間で競合するリソースを使用する順序を調整する

2.複数のプロセスを同時に実行することで、リソースを有効に活用し、相互に連携できるようにする

2つ目は、プロセス間の同期の原則です。

重要なリソース:重要なリソースとは、共有リソースであるが、複数のプロセスまたはスレッドから同時にアクセスできない共有リソースを指します。プロセスがストリートリソースを使用する場合、他のプロセスは、オペレーティングシステムの同期メカニズムに従って、占有されているプロセスが共有リソースを解放するのを待ってから、共有リソースを再度競合する必要があります。

重要なリソースを効果的に制約するために、プロセス間の同期の4つの原則が提案されています

  • アイドル状態の取り込み:リソースは占有されておらず、使用が許可されていません
  • ビジーの場合は待機中:リソースが占有されており、要求プロセスが待機中です
  • 限られた待機:限られた待機時間でリソースを使用できることを保証し、他の待機プロセスが停止するのを防ぎます
  • 待機する力を与える:待機するとき、プロセスはCPUを放棄する必要があります。つまり、プロセスは実行状態からブロッキング状態に変わります。これは、CPUを効率的に使用できるようにするための前提条件でもあります。

プロセス間の同期方法:
メッセージキュー、共有ストレージ、セマフォ。これらのプロセス間の同期方法については、後の記事で詳しく説明します。

3、スレッドの同期

前回の記事「プロセス管理のプロセスエンティティ」から、プロセスには1つ以上のスレッドがあり、スレッドはプロセスリソースを共有していることがわかります。ここで質問があります。複数のスレッドがプロセスリソースを同時に使用するとどうなりますか?実際、上記の生産者/消費者問題と哲学者の食事の問題も発生するため、プロセス内のスレッドは同時に共有リソースを使用するため、プロセス内のマルチスレッドも同期する必要があると結論付けます。処理する

スレッド同期方法

  • Mutex:これは、複数のスレッドが相互に排他的に重要なリソースにアクセスできることを保証するロックです
  • 読み取り/書き込みロック:これは、読み取りが多く、書き込みが少ない、または書き込みが多く、読み取りが少ない状況に対処するために考案されたロックです。
  • スピンロック
  • 条件変数

これらのメソッドについては、後の記事でも詳しく紹介します。

急速に変化するテクノロジーの常識を見つけることは、技術者のコアコンピタンスです。理論と実践を組み合わせた知識と行動の統一
ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/self_realian/article/details/106982942