Linux のさまざまなロックメカニズムの使用方法と違いについて詳しく説明します

Linux のさまざまなロックメカニズムの使用方法と違いについて詳しく説明します

序文:

この知識を理解する必要がある人は、すでにプロセス間通信とスレッド間通信の基本的な理解を持っていると思います。たとえば、プロセス間通信のメカニズムの 1 つは共有メモリです (ここでは詳しく説明しません)。複数のプロセスが同時に同じメモリ ブロックにアクセスできます。このメモリにアクセスするクリティカル セクションが相互に排他的または同期されていない場合、プロセスの実行で予期しないエラーや結果が発生する可能性があります。

次に、Linux での 3 つの一般的な排他操作、つまりロックについて学習します。

1. ミューテックス

機能:読者と作家向け。一方がロックを取得している限り、もう一方はロックを取得し続けてクリティカル セクション コードを実行することはできません。

ロックを作成します。

ミューテックスを作成するには、静的と動的の 2 つの方法があります。 POSIX は、ミューテックスを静的に初期化するためのマクロ PTHREAD_MUTEX_INITIALIZER を定義します。

方法は次のとおりです。

pthread_mutex_t ミューテックス=PTHREAD_MUTEX_INITIALIZER;

LinuxThreads 実装では、pthread_mutex_t は構造体であり、PTHREAD_MUTEX_INITIALIZER は構造体定数です。

動的な方法は、pthread_mutex_init() 関数を使用してミューテックス ロックを初期化することです。API 定義は次のとおりです。

pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t*mutexattr) スレッドのミューテックスを初期化します。

mutexattr は、ミューテックス属性を指定するために使用されます (以下を参照)。NULL の場合、デフォルトの属性が使用されます。 pthread_mutex_destroy() はミューテックスをキャンセルするために使用されます。API 定義は次のとおりです。

pthread_mutex_destroy() メソッドは、ミューテックスを破棄します。

ロック操作には、主に pthread_mutex_lock() のロック、pthread_mutex_unlock() のロック解除、pthread_mutex_trylock() のロック テストが含まれます。どのタイプのロックでも、2 つの異なるスレッドが同時にロックを取得することは不可能であり、ロック解除されるまで待機する必要があります。通常のロックと適応型ロック タイプの場合、ロック解除者は同じプロセス内の任意のスレッドにすることができます。一方、エラー検出ロックは、有効にするにはロック保持者がロックを解除する必要があります。そうでない場合は EPERM が返されます。ネストされたロックの場合、ドキュメントと実装ではロック保持者がロックを解除する必要がありますが、実験結果ではそのような制限がないことが示されています。この違いはまだ説明されていません。同じプロセス内のスレッドがブロックをロックしたがロックを解除していない場合、他のスレッドはロックを取得できません。

pthread_mutex_lock(pthread_mutex_t *ミューテックス) 
pthread_mutex_unlock(pthread_mutex_t *ミューテックス) 
pthread_mutex_trylock() メソッドは、ミューテックスをロックします。

pthread_mutex_trylock() のセマンティクスは pthread_mutex_lock() のセマンティクスと似ていますが、ロックがすでに占有されている場合に待機するのではなく EBUSY を返す点が異なります。
たとえば、シングルトン モードでは、スレッドセーフ ロックは次のようになります。

クラス SingleTon 
{ 
公共: 
静的シングルトン* getInstance() 
{ 
pthread_mutex_lock(&mutex); 
if(mpSingle == NULL) 
{ 
mpSingleTon = 新しいSingleTon(); 
} 
pthread_mutex_unlock(&mutex); 
mpSingleTon を返します。 
} 
プライベート: 
シングルトン(){}; 
~シングルトン(){pthread_mutex_desttroy(&mutex,NULL);} 
静的 pthread_mutex_t ミューテックス; 
静的シングルトン *mpSingleTon; 
} 
pthread_mutex_t シングルトン::mutex = PTHREAD_MUTEX_INITIALIZER; 
シングルトン * シングルトン::mpSingleTon = NULL;

アドバンテージ:

これは、複数のプロセスで共有できるメモリ空間 (整列された整数変数) で構成されます。この整数変数の値は、CPU によってアセンブリ言語で提供されるアトミック操作命令を呼び出すことによって増減でき、プロセスはその値が正の数になるまで待機できます。 ほぼすべての操作はアプリケーション空間で完了します。操作結果に矛盾があり、調停が必要な場合にのみ、オペレーティング システム カーネル空間に入って実行する必要があります。このメカニズムにより、非常に高い実行効率でロック プリミティブを使用できます。ほとんどの操作では複数のプロセス間の調停が必要ないため、ほとんどの操作は (比較的高価な) カーネル システム コールを使用せずにアプリケーション空間で実行できます。

2. 読み取り書き込みロック

特徴:読み取り/書き込みロックは、データ構造の読み取り回数が書き込み回数よりはるかに多い状況に適しています。読み取りモードでロックすると共有でき、書き込みモードでロックすると排他的になるため、読み取り/書き込みロックは共有排他ロックとも呼ばれます。

初期化と破棄:

int pthread_rwlock_init(pthread_rwlock_t *制限付きrwlock, const 
pthread_rwlockattr_t *属性を制限します。 
pthread_rwlock_t は rwlock を破棄します。

成功した場合は 0 を返し、エラーが発生した場合はエラー番号を返します。ミューテックスと同様に、読み取り/書き込みロックによって占有されているメモリを解放する前に、pthread_rwlock_destroy を介して読み取り/書き込みロックをクリーンアップし、init によって割り当てられたリソースを解放する必要があります。

読み取りと書き込み:

pthread_rwlock_t は rwlock を呼び出します。 
pthread_rwlock_t は rwlock を呼び出します。 
pthread_rwlock_t のロックを解除します。

成功した場合は 0 を返し、エラーが発生した場合はエラー番号を返します。これらの 3 つの関数は、それぞれ読み取りロックの取得、書き込みロックの取得、ロックの解放の操作を実装します。ロックを取得するための 2 つの関数はブロッキング操作です。同様に、非ブロッキング関数は次のとおりです。

pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); 
pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

成功した場合は 0 を返し、エラーが発生した場合はエラー番号を返します。非ブロッキング ロック取得操作の場合、ロックを取得できる場合は 0 を返し、それ以外の場合はエラー EBUSY を返します。

3. スピンロック

機能:ポーリングビジー待機。

シングルコア CPU では動作しません。スピン ロックによって保護されたクリティカル セクション コードは実行中に中断できません。デッドロックを引き起こすスピンロックの本来の目的は、短時間で軽量なロックを実行することです。競合するスピン ロックにより、ロックが再び使用可能になるまで待機している間、スピン ロックを要求するスレッドがスピンすることになります (これはプロセッサ時間の無駄です)。そのため、スピン ロックは長時間保持しないでください。長時間ロックする必要がある場合は、セマフォを使用することをお勧めします。

API:

要約する

上記はこの記事の全内容です。この記事の内容が皆さんの勉強や仕事に一定の参考学習価値を持つことを願っています。ご質問があれば、メッセージを残してコミュニケーションしてください。123WORDPRESS.COM を応援していただきありがとうございます。

以下もご興味があるかもしれません:
  • Linux シェルでの配列と for ループのトラバーサル メソッドの定義
  • Linux シェル配列ループの詳細な例
  • Linuxターミナルでシェルスクリプトを実行して現在実行中のアプリのログを直接出力するAndroidの実装方法
  • pyqt を使用して Linux コマンド プログラムをリモートでバッチ実行する方法
  • Linux シェル環境での Zabbix API の使用
  • Linux で誤って削除したメッセージ ファイルを復元する方法
  • Linuxカーネルマクロcontainer_ofの詳細な分析
  • Linux のロード vmlinux デバッグ
  • Linux で指定されたフォルダの各サブフォルダ内のファイル数を表示する
  • Linux シェル配列と連想配列の使用例

<<:  MySQL での数値のフォーマットの詳細な説明

>>:  Reactはラジオコンポーネントのサンプルコードを実装します

推薦する

Linux 上の Tomcat で MySQL にデータを挿入するときに中国語の文字化けが発生する問題を解決する

1. 問題Windows 上の Eclipse を使用して開発されたプロジェクトは Windows ...

docker-compose で Jenkins をインストールする際の実践的なメモ

ディレクトリを作成する cd /usr/local/docker/ jenkins-docker を...

mysql 5.7.18 winx64 無料インストール設定方法

1. ダウンロード2. 減圧3. パス環境変数を追加し、mysqlが配置されているbinディレクトリ...

クリック範囲を拡大する入力チェックボックスを実装する方法

XML/HTML コードコンテンツをクリップボードにコピー< div style = &quo...

Nginx は https ウェブサイト構成コード例を実装します

https ベースポート 443。これはキーと呼ばれるものに使用されます。これらのことを理解せずにで...

デプロイから基本操作までDocker Swarm

Docker SwarmについてDocker Swarm は次の 2 つの部分で構成されます。 D...

JavaScriptは組み込みオブジェクトのプロトタイプメソッド実装を追加します

オブジェクトがメソッドを呼び出す順序:インスタンス内にメソッドが存在しない場合は、インスタンス オブ...

Linux システムで Code Cloud にプロジェクトをアップロードする方法

Code Cloudで新しいプロジェクトtest1を作成します。 公開鍵を取得するには次のコマンドを...

CentOS での samba フォルダ共有サーバー構成の詳細な説明

1. はじめに最近、CentOS での開発には多くの不便があることがわかりました。Windows/M...

MySQL 選択最適化ソリューションに関する簡単な説明

目次実生活からの例クエリが遅い最適化する方法カウント制限最大値と最小値 min&max実生活...

Vue で eslint 検出をオフにする方法 (複数の方法)

目次1. 問題の説明2. 問題解決1. 問題の説明Vue プロジェクトを開発する場合、作成時に誤って...

Dockerが新しいイメージをロードした後にリポジトリとタグ名が両方ともnoneになる問題を解決する

次のコマンドを使用できます: docker tag [イメージID] [名前]:[バージョン]例えば...

Docker環境でJenkinsを設定すると、タスクをビルドするときにコンソールログに文字化けした中国語の文字が表示されます

目次1. 問題の説明: 2. Jenkins設定のトラブルシューティング3. コードログのエンコード...

MySQL における KEY、PRIMARY KEY、UNIQUE KEY、INDEX の違い

タイトルで提起された問題は、段階的に分解して解決することができます。 MySQL では KEY と ...

MySQL ストアド プロシージャと共通関数のコード分析

mysql ストアド プロシージャの概念:特定のタスク (クエリと更新) を実行できる、データベース...