Linux プロセス間通信の効率的な方法: 共有メモリの使用
次に、共有メモリを使用したプロセス間通信の別の方法について説明します。
1. 共有メモリとは
名前が示すように、共有メモリを使用すると、無関係な 2 つのプロセスが同じ論理メモリにアクセスできます。共有メモリは、実行中の 2 つのプロセス間でデータを共有および転送するための非常に効率的な方法です。異なるプロセス間で共有されるメモリは、通常、物理メモリの同じセグメントとして配置されます。プロセスは、共有メモリの同じセグメントを独自のアドレス空間に接続でき、すべてのプロセスは、C 言語関数 malloc を使用して割り当てられたメモリであるかのように、共有メモリ内のアドレスにアクセスできます。また、プロセスが共有メモリにデータを書き込むと、その変更は共有メモリの同じセグメントにアクセスできる他のプロセスに直ちに影響します。
特別な注意: 共有メモリには同期メカニズムがありません。つまり、最初のプロセスが共有メモリへの書き込みを完了する前に、2 番目のプロセスが共有メモリの読み取りを開始するのを防ぐ自動メカニズムはありません。したがって、通常は、前述のセマフォなどの他のメカニズムを使用して、共有メモリへのアクセスを同期する必要があります。セマフォの詳細については、私の他の記事「Linux プロセス間通信 - セマフォの使用」を参照してください。
2. 共有メモリの使用方法
セマフォと同様に、Linux も共有メモリを使用するための一連の機能インターフェイスを提供します。共有共存を使用するインターフェイスはセマフォのインターフェイスと非常によく似ており、セマフォを使用するインターフェイスよりも単純です。これらはヘッダー ファイル sys/shm.h で宣言されます。1.shmget 関数
この関数は共有メモリを作成するために使用されます。そのプロトタイプは次のとおりです:
- int shmget(key_t キー, size_t サイズ, int shmflg);
が返されます。
無関係なプロセスは、プログラムが使用する可能性のあるリソースを表すこの関数の戻り値を通じて同じ共有メモリにアクセスできます。プログラムによるすべての共有メモリへのアクセスは間接的です。プログラムは最初に shmget 関数を呼び出し、A キーを提供します, その後、システムは対応する共有メモリ識別子 (shmget 関数の戻り値) を生成します。shmget 関数のみがセマフォ キーを直接使用し、他のすべてのセマフォ関数は semget 関数によって返されたセマフォ識別子を使用します。2 番目のパラメータの size は、共有されるメモリ容量をバイト単位で指定します。
3 番目のパラメータ shmflg は許可フラグです。その機能は open 関数の mode パラメータと同じです。キーで指定された共有メモリが存在しない場合に作成したい場合は、次の操作を行うか操作できます。 IPC_CREATを使用して。共有メモリの許可フラグは、ファイルの読み取りおよび書き込み許可と同じです。たとえば、0644 は、プロセスによって作成された共有メモリは、所有するプロセスによる共有メモリへの読み取りおよび書き込みが許可されていることを意味します。同時に、他のユーザーが作成したプロセスは共有メモリの読み取りのみ可能です。
2. shmat 関数
共有メモリが初めて作成されるときは、どのプロセスからもアクセスできません。shmat 関数の機能は、共有メモリへのアクセスを開始し、共有メモリを現在のプロセスのアドレス空間に接続することです。そのプロトタイプは次のとおりです:
リーリー- 最初のパラメータ shm_id は、shmget 関数によって返される共有メモリ ID です。
2 番目のパラメータ shm_addr は、共有メモリが現在のプロセスに接続されているアドレスの場所を指定します。通常は空であり、システムが共有メモリのアドレスを選択できることを示します。
3 番目のパラメータ shm_flg はフラグ ビットのセットで、通常は 0 です。
呼び出しが成功すると、共有メモリの最初のバイトへのポインタが返され、呼び出しが失敗した場合は、-1 が返されます。
3. shmdt 関数この関数は、現在のプロセスから共有メモリを切り離すために使用されます。共有メモリを切り離しても、共有メモリは削除されず、共有メモリが現在のプロセスで使用できなくなるだけであることに注意してください。そのプロトタイプは次のとおりです:
リーリー
パラメータ shmaddr は、shmat 関数によって返されるアドレス ポインタです。呼び出しが成功した場合は 0 を返し、失敗した場合は -1 を返します。4. shmctl 関数
セマフォの semctl 関数と同様、共有メモリの制御に使用されます。プロトタイプは次のとおりです。
-
**int** shmctl(**int** shm_id, **int** command, **struct** shmid_ds *buf);
ログイン後にコピー
第一个参数,shm_id是shmget函数返回的共享内存标识符。
第二个参数,command是要采取的操作,它可以取下面的三个值 :
IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。
IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值
IPC_RMID:删除共享内存段
第三个参数,buf是一个结构指针,它指向共享内存模式和访问权限的结构。
shmid_ds结构至少包括以下成员:
1. struct** shmid_ds 2. { 3. uid_t shm_perm.uid; 4. uid_t shm_perm.gid; 5. mode_t shm_perm.mode; 6. };
三、使用共享内存进行进程间通信
说了这么多,又到了实战的时候了。下面就以两个不相关的进程来说明进程间如何通过共享内存来进行通信。其中一个文件shmread.c创建共享内存,并读取其中的信息,另一个文件shmwrite.c向共享内存中写入数据。为了方便操作和数据结构的统一,为这两个文件定义了相同的数据结构,定义在文件shmdata.c中。结构shared_use_st中的written作为一个可读或可写的标志,非0:表示可读,0表示可写,text则是内存中的文件。
shmdata.h的源代码如下:
1. \#ifndef _SHMDATA_H_HEADER 2. \#define _SHMDATA_H_HEADER 3. 4. \#define TEXT_SZ 2048 5. 6. **struct** shared_use_st 7. { 8. **int** written;//作为一个标志,非0:表示可读,0表示可写 9. **char** text[TEXT_SZ];//记录写入和读取的文本 10. }; 11. 12. \#endif
源文件shmread.c的源代码如下:
-
1. \#include 2. \#include 3. \#include 4. \#include 5. \#include "shmdata.h" 6. 7. **int** main() 8. { 9. **int** running = 1;//程序是否继续运行的标志 10. **void** *shm = NULL;//分配的共享内存的原始首地址 11. **struct** shared_use_st *shared;//指向shm 12. **int** shmid;//共享内存标识符 13. //创建共享内存 14. shmid = shmget((key_t)1234, **sizeof**(**struct** shared_use_st), 0666|IPC_CREAT); 15. **if**(shmid == -1) 16. { 17. fprintf(stderr, "shmget failed\n"); 18. exit(EXIT_FAILURE); 19. } 20. //将共享内存连接到当前进程的地址空间 21. shm = shmat(shmid, 0, 0); 22. **if**(shm == (**void***)-1) 23. { 24. fprintf(stderr, "shmat failed\n"); 25. exit(EXIT_FAILURE); 26. } 27. printf("\nMemory attached at %X\n", (**int**)shm); 28. //设置共享内存 29. shared = (**struct** shared_use_st*)shm; 30. shared->written = 0; 31. **while**(running)//读取共享内存中的数据 32. { 33. //没有进程向共享内存定数据有数据可读取 34. **if**(shared->written != 0) 35. { 36. printf("You wrote: %s", shared->text); 37. sleep(rand() % 3); 38. //读取完数据,设置written使共享内存段可写 39. shared->written = 0; 40. //输入了end,退出循环(程序) 41. **if**(strncmp(shared->text, "end", 3) == 0) 42. running = 0; 43. } 44. **else**//有其他进程在写数据,不能读取数据 45. sleep(1); 46. } 47. //把共享内存从当前进程中分离 48. **if**(shmdt(shm) == -1) 49. { 50. fprintf(stderr, "shmdt failed\n"); 51. exit(EXIT_FAILURE); 52. } 53. //删除共享内存 54. **if**(shmctl(shmid, IPC_RMID, 0) == -1) 55. { 56. fprintf(stderr, "shmctl(IPC_RMID) failed\n"); 57. exit(EXIT_FAILURE); 58. } 59. exit(EXIT_SUCCESS); 60. }
ログイン後にコピー
源文件shmwrite.c的源代码如下:
1. \#include 2. \#include 3. \#include 4. \#include 5. \#include 6. \#include "shmdata.h" 7. 8. **int** main() 9. { 10. **int** running = 1; 11. **void** *shm = NULL; 12. **struct** shared_use_st *shared = NULL; 13. **char** buffer[BUFSIZ + 1];//用于保存输入的文本 14. **int** shmid; 15. //创建共享内存 16. shmid = shmget((key_t)1234, **sizeof**(**struct** shared_use_st), 0666|IPC_CREAT); 17. **if**(shmid == -1) 18. { 19. fprintf(stderr, "shmget failed\n"); 20. exit(EXIT_FAILURE); 21. } 22. //将共享内存连接到当前进程的地址空间 23. shm = shmat(shmid, (**void***)0, 0); 24. **if**(shm == (**void***)-1) 25. { 26. fprintf(stderr, "shmat failed\n"); 27. exit(EXIT_FAILURE); 28. } 29. printf("Memory attached at %X\n", (**int**)shm); 30. //设置共享内存 31. shared = (**struct** shared_use_st*)shm; 32. **while**(running)//向共享内存中写数据 33. { 34. //数据还没有被读取,则等待数据被读取,不能向共享内存中写入文本 35. **while**(shared->written == 1) 36. { 37. sleep(1); 38. printf("Waiting...\n"); 39. } 40. //向共享内存中写入数据 41. printf("Enter some text: "); 42. fgets(buffer, BUFSIZ, stdin); 43. strncpy(shared->text, buffer, TEXT_SZ); 44. //写完数据,设置written使共享内存段可读 45. shared->written = 1; 46. //输入了end,退出循环(程序) 47. **if**(strncmp(buffer, "end", 3) == 0) 48. running = 0; 49. } 50. //把共享内存从当前进程中分离 51. **if**(shmdt(shm) == -1) 52. { 53. fprintf(stderr, "shmdt failed\n"); 54. exit(EXIT_FAILURE); 55. } 56. sleep(2); 57. exit(EXIT_SUCCESS); 58. }
再来看看运行的结果:
分析:
1、程序shmread创建共享内存,然后将它连接到自己的地址空间。在共享内存的开始处使用了一个结构struct_use_st。该结构中有个标志written,当共享内存中有其他进程向它写入数据时,共享内存中的written被设置为0,程序等待。当它不为0时,表示没有进程对共享内存写入数据,程序就从共享内存中读取数据并输出,然后重置设置共享内存中的written为0,即让其可被shmwrite进程写入数据。
2、程序shmwrite取得共享内存并连接到自己的地址空间中。检查共享内存中的written,是否为0,若不是,表示共享内存中的数据还没有被完,则等待其他进程读取完成,并提示用户等待。若共享内存的written为0,表示没有其他进程对共享内存进行读取,则提示用户输入文本,并再次设置共享内存中的written为1,表示写完成,其他进程可对共享内存进行读操作。
四、关于前面的例子的安全性讨论
这个程序是不安全的,当有多个程序同时向共享内存中读写数据时,问题就会出现。可能你会认为,可以改变一下written的使用方式,例如,只有当written为0时进程才可以向共享内存写入数据,而当一个进程只有在written不为0时才能对其进行读取,同时把written进行加1操作,读取完后进行减1操作。这就有点像文件锁中的读写锁的功能。咋看之下,它似乎能行得通。但是这都不是原子操作,所以这种做法是行不能的。试想当written为0时,如果有两个进程同时访问共享内存,它们就会发现written为0,于是两个进程都对其进行写操作,显然不行。当written为1时,有两个进程同时对共享内存进行读操作时也是如些,当这两个进程都读取完是,written就变成了-1.
要想让程序安全地执行,就要有一种进程同步的进制,保证在进入临界区的操作是原子操作。例如,可以使用前面所讲的信号量来进行进程的同步。因为信号量的操作都是原子性的。
五、使用共享内存的优缺点
1、优点:我们可以看到使用共享内存进行进程间的通信真的是非常方便,而且函数的接口也简单,数据的共享还使进程间的数据不用传送,而是直接访问内存,也加快了程序的效率。同时,它也不像匿名管道那样要求通信的进程有一定的父子关系。
2、缺点:共享内存没有提供同步的机制,这使得我们在使用共享内存进行进程间通信时,往往要借助其他的手段来进行进程间的同步工作。
以上がLinux プロセス間通信の効率的な方法: 共有メモリの使用の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











多くのユーザーにとって、Android TV ボックスをハッキングするのは気が遠くなるように思えます。しかし、開発者の Murray R. Van Luyn は、Broadcom チップが不足する中、Raspberry Pi に代わる適切な代替品を探すという課題に直面しました。アルムビアとの共同作業

DeepSeekは、Webバージョンと公式Webサイトの2つのアクセス方法を提供する強力なインテリジェント検索および分析ツールです。 Webバージョンは便利で効率的であり、公式ウェブサイトは包括的な製品情報、ダウンロードリソース、サポートサービスを提供できます。個人であろうと企業ユーザーであろうと、DeepSeekを通じて大規模なデータを簡単に取得および分析して、仕事の効率を向上させ、意思決定を支援し、イノベーションを促進することができます。

DeepSeekをインストールするには、Dockerコンテナ(最も便利な場合は、互換性について心配する必要はありません)を使用して、事前コンパイルパッケージ(Windowsユーザー向け)を使用してソースからコンパイル(経験豊富な開発者向け)を含む多くの方法があります。公式文書は慎重に文書化され、不必要なトラブルを避けるために完全に準備します。

BitPie Bitpie ウォレット アプリをダウンロードするにはどうすればよいですか?手順は次のとおりです。 AppStore (Apple デバイス) または Google Play ストア (Android デバイス) で「BitPie Bitpie Wallet」を検索します。 「入手」または「インストール」ボタンをクリックしてアプリをダウンロードします。コンピューター版の場合は、BitPie ウォレットの公式 Web サイトにアクセスし、対応するソフトウェア パッケージをダウンロードしてください。

Bitgetは、スポット取引、契約取引、デリバティブなど、さまざまな取引サービスを提供する暗号通貨交換です。 2018年に設立されたこのExchangeは、シンガポールに本社を置き、安全で信頼性の高い取引プラットフォームをユーザーに提供することに取り組んでいます。 Bitgetは、BTC/USDT、ETH/USDT、XRP/USDTなど、さまざまな取引ペアを提供しています。さらに、この取引所はセキュリティと流動性について評判があり、プレミアム注文タイプ、レバレッジド取引、24時間年中無休のカスタマーサポートなど、さまざまな機能を提供します。

1. インストール環境 (Hyper-V 仮想マシン): $hostnamectlStatichostname:localhost.localdomainIconname:computer-vmChassis:vmMachineID:renwoles1d8743989a40cb81db696400BootID:renwoles272f4aa59935dcdd0d456501Virtualization:microsoftOperatingSystem:CentOS Linux7(Core)CPEOSName: CP:

世界をリードするデジタル資産交換であるOuyi Okxは、安全で便利な取引体験を提供するために、公式のインストールパッケージを開始しました。 OUYIのOKXインストールパッケージは、ブラウザに直接インストールでき、ユーザー向けの安定した効率的な取引プラットフォームを作成できます。インストールプロセスは、簡単で理解しやすいです。

Gate.ioは、インストールパッケージをダウンロードしてデバイスにインストールすることで使用できる人気のある暗号通貨交換です。インストールパッケージを取得する手順は次のとおりです。Gate.ioの公式Webサイトにアクセスし、「ダウンロード」をクリックし、対応するオペレーティングシステム(Windows、Mac、またはLinux)を選択し、インストールパッケージをコンピューターにダウンロードします。スムーズなインストールを確保するために、インストール中に一時的にウイルス対策ソフトウェアまたはファイアウォールを一時的に無効にすることをお勧めします。完了後、ユーザーはGATE.IOアカウントを作成して使用を開始する必要があります。
