1. 実験の目的
この実験を通じて、プロセスの概念の理解を深め、プロセスとプログラムの違いを明確にし、同時実行の本質を認識し、LinuxおよびWindowsのプロセス通信システムコールの機能を理解して使いこなし、プロセスシステムコールのプログラミングを向上させます。実験と学習を通じて、セマフォ機構を使用してプロセス間の同期と排他を完了する方法を習得します。
2. 実験内容
Windows オペレーティング システムで 6 つのバッファを持つバッファ プールを作成します。最初は空で、各バッファには 10 文字の文字列を格納できます。また、2 つのプロデューサーと 3 つのコンシューマーを同時に作成し、プロデューサーまたはコンシューマーをモックするプロセスを使用します。
プロデューサの場合、ランダムな期間待機した後、データをバッファに保存します。バッファがいっぱいの場合は、コンシューマがデータを取得するのを待ってから保存します。各プロデューサはデータを 12 回保存します。
コンシューマの場合、一定期間ランダムに待機した後、バッファからデータをフェッチします。バッファが空の場合は、プロデューサがデータを格納するのを待ってからフェッチします。各コンシューマはデータを 8 回フェッチします。
バッファーに追加またはバッファーから取得されるデータと時刻を毎回表示し、各操作後のバッファー内のすべてのデータとプロデューサーおよびコンシューマーのプロセス番号を表示します。
3. プログラムの設計と実装
1. 実験環境
仮想マシン: CentOS 7
オペレーティングシステム: Windows10
開発環境:RedPanda-Cpp.0.14.2.64bit.10.3
2. デザインアイデア
① 共有メモリ領域を定義する
構造体 BUF {
文字配列[BufAmount][BufLen];
整数頭;
intテール;
int IsEmpty ;
};
共有メモリ領域の配列は、プロデューサとコンシューマがデータにアクセスするためのリング バッファを表し、そのサイズ BufAmount を 6 に、単一データ長 BufLen を 10 に設定します。ポインタの先頭は、コンシューマが次回フェッチするデータを指すために使用され、ポインタの末尾は、プロデューサが次回データを保存する必要があるバッファを指します。IsEmpty は、リング バッファが空であるかどうかを示すために使用されます。0は空ではないことを意味し、1は空であることを意味します。
②セマフォを設定する
実験では、次のように 3 つのセマフォを設定します。
相互排他セマフォMUTEX : プロデューサプロセスとプロデューサプロセス、コンシューマプロセスとプロデューサプロセス、コンシューマプロセスとコンシューマプロセス間の相互排他バッファに使用され、初期値は1です。
同期セマフォEMPTY : 現在利用可能な空のバッファーの数を示すために使用され、プロデューサー プロセスがバッファーにデータを格納することを制限するために使用されます。初期値は 6 です。
同期セマフォFULL : 現在データを持つバッファーの数を示すために使用され、コンシューマー プロセスによるデータのフェッチを制限するために使用されます。初期値は 0 です。
③プロデューサーのセーブデータ
(1) GetRandomChar()、GetRandomNum():可変長の文字列をランダムにデータとして生成します。
(2) Sleep(GetRandomSleep()): ランダムに待機します。
(2) P(EMPTY): 空のバッファユニット EMPTY-1 に適用します。
(4) P(MUTEX): リングバッファの唯一の使用権 MUTEX-1 を申請します。
(5) strcpy(pbuf->array[pbuf->tail],charray): プロデューサプロセスはデータをバッファに格納します。
(6) pbuf->tail=(pbuf->tail+1)%BufAmount: 次のバッファ ユニットを指すようにテール ポインタを変更します。
(7) pbuf->IsEmpty=1: バッファステータス IsEmpty を変更します。
(8) V(MUTEX): プロデューサプロセスはリングバッファの使用権を解放します (MUTEX+1)
(9) V(FULL): FULL+1、リング バッファ内の利用可能なデータの総量を示し、コンシューマ プロセスをウェイクアップします。
④ コンシューマがデータを取得する
(1) Sleep(GetRandomSleep()): ランダムに待機します。
(2) P(FULL): データを含むバッファユニット、FULL-1 を適用します。
(3) P(MUTEX): リングバッファの唯一の使用権 MUTEX-1 を申請します。
(4) strcpy(charray,pbuf->array[pbuf->head]): 現在の head ポインタが指すデータを取得します。 (5) memset(pbuf->array[pbuf->head,'\0', sizeof(pbuf ->array[pbuf->head])) : このデータが保存されているバッファー位置の内容をクリアします。
(6) pbuf->IsEmpty=(pbuf->head==pbuf->tail): バッファのステータスを変更します。
(7) pbuf->head=(pbuf->head+1)%BufAmount: 次のバッファユニットを指すようにポインタを変更します。
(8) V(MUTEX): コンシューマプロセスはリングバッファの使用権を解放します。
(9) V(EMPTY): Empty+1。ウェイクアップに使用される、リング バッファ内の空のバッファ ユニットの数を示します。
プロデューサー プロセスはデータをバッファーに保存します。
生産と消費のプロセスでは、バッファーがいっぱいでプロデューサーがまだデータを入れている状況を避けるために、コンシューマーまたはプロデューサーがバッファー ユニットを申請できるかどうかを制御する同期セマフォ FULL および EMPTY があります。は空ですが、コンシューマーはまだデータの状態を取得しています。
さらに、MUTEX の存在により、各プロセスがリング バッファを相互に排他的に使用できることが保証され、MUTEX、FULL、および EMPTY の適切な組み合わせにより、デッドロックが発生しないことが保証されます。
3. コードを記述してコンパイルする
開発環境で C++ コードを作成し、関連するインターフェイスを呼び出して対応する機能を実現します。
4. 実行して結果を取得します
4. 実験結果と解析
操作中、プロセスを通じて 2 つのプロデューサー (番号 16864、10052) がシミュレートされ、3 つのコンシューマー (番号 21408、19796、21068) がシミュレートされます。
2022 年 10 月 5 日 11:43:19 から 11:43:37 までに、親プロセスは 24 回のデータ保存と 24 回のデータ取得プロセスを完了し、リング バッファーが空から満杯になり、その後再び空になり、文字列が実現されました。データアクセス、「生産者消費者問題」が解決されます。
実験結果を下図に示します。
5. 実験収穫と体験
「生産者消費者問題」はセマフォ知識の非常に典型的な事例ですが、この実験を通じてプロセスの概念への理解をさらに深め、同時実行の本質を深く理解することができました。
在Windows操作系统里,我利用信号量机制用进程模拟生产者和消费者,完成了进程间的同步和互斥。在看到正确运行结果的那一刻,我觉得编写与修改代码所付出的一切辛苦都是值得的。
在亲自动手实验的过程中,我对信号量知识点有了更深刻的理解,同时也复习了程序设计方面的知识,真可谓“一举两得”,这次实验让我收获颇多!
源码及实验报告:https://github.com/YourHealer/OS-Producer-and-Consumer.git