Linux でのマルチスレッド同期にはどのような方法がありますか?
同期方法には次のものが含まれます: 1. ミューテックス ロックは、ロックとロック解除の 2 つの状態を持つ特別なグローバル変数です。ロック解除ミューテックス ロックは、特定のスレッドによって取得できます。ミューテックス ロックが特定のスレッドによって保持されている場合、その後, ミューテックスはロックされ、ロック状態になります。その後、スレッドだけがロックを開く権限を持ちます。2. スピン ロックは無限ループであり、常にポーリングします。3. セマフォはカウンターです。制御に使用されます。制限された共有リソースにアクセスするスレッドの数、4. 条件変数、5. 読み取り/書き込みロック、6. ユーザーが複数のスレッドの並列作業を調整するための同期メカニズムであるバリア。
#このチュートリアルの動作環境: linux7.3 システム、Dell G3 コンピューター。
スレッドの同期とは、スレッドが重要なリソースで動作しているとき、他のスレッドはこのリソースで動作できないことを意味します。スレッドが動作を完了するまで、他のスレッドは動作できます。これは協調的なペースです。これにより、スレッドは次のことを行うことができます。あらかじめ決められた順序で実行されます。スレッド同期には、ミューテックス ロック、スピン ロック、セマフォ、条件変数、読み取り/書き込みロック、バリアの 6 つの方法があります。
Linux スレッド同期方法
#include<stdio.h> #include<pthread.h> int ticket_num=10000000; void *sell_ticket(void *arg) { while(ticket_num>0) { ticket_num--; } } int main() { pthread_t t1,t2,t3; pthread_create(&t1, NULL, &sell_ticket, NULL); pthread_create(&t2, NULL, &sell_ticket, NULL); pthread_create(&t3, NULL, &sell_ticket, NULL); pthread_join(t1, NULL); pthread_join(t2, NULL); pthread_join(t3, NULL); printf("ticket_num=%d\n", ticket_num); return 0; }
実行結果は次のとおりです:
# gcc no_lock_demo.c -o no_lock_demo.out -pthread # ./no_lock_demo.out ticket_num=-2
最終的な実行結果は固定されておらず、0 または -1 になる可能性があります。在庫を表すこの ticket_num 変数がある場合、在庫は負になるため、スレッドが必要です同期はスレッドの安全性を確保するために導入されています。
Linux では、スレッド同期を処理するさまざまな方法が提供されています。最も一般的に使用されるのは、ミューテックス ロック、スピン ロック、セマフォです。
1. ミューテックス ロック
ミューテックス ロックの本質は、ロックとロック解除の 2 つの状態を持つ特別なグローバル変数です。ロック解除ミューテックス ロックは制御できます。特定のスレッドによってミューテックスが取得されます。ミューテックスがスレッドによって保持されると、そのミューテックスはロックされ、ロック状態になります。その後、そのスレッドだけがロックを開く権限を持ち、他のスレッドはロックを取得したいと考えます。ミューテックスは、ロックが解除されるまでブロックされます。
ミューテックス ロックのタイプ:
通常のロック (PTHREAD_MUTEX_NORMAL): ミューテックス ロックのデフォルトのタイプ。スレッドが共通ロックをロックすると、ロックを要求した残りのスレッドは待機キューを形成し、ロックが解除された後、優先順位に従ってロックを取得するため、リソース割り当ての公平性が確保されます。ロックされている通常のロックをスレッドが再度ロックすると、デッドロックが発生します。別のスレッドによってロックされた通常のロックをアンロックしたり、アンロックされた通常のロックを再度アンロックすると、予期しない結果が生じます。
エラーチェック ロック (PTHREAD_MUTEX_ERRORCHECK): スレッドがすでにロックされているエラーチェック ロックを再度ロックすると、ロック操作は EDEADLK を返します (別のスレッドによってロックされているスレッドの場合)。異常検出ロックを解除するか、すでに解除されている異常検出ロックを再度解除すると、解除動作は EPERM に戻ります。
ネストされたロック (PTHREAD_MUTEX_RECURSIVE): このロックを使用すると、スレッドはデッドロックなしでロックを解放する前に複数回ロックできます。他のスレッドがこのロックを取得したい場合は、現在のロックを所有者が取得する必要があります。複数のロック解除操作を実行します。別のスレッドによってロックされているネストされたロックをロック解除する場合、またはすでにロック解除されているネストされたロックを再度ロック解除する場合、ロック解除操作は EPERM を返します。
デフォルト ロック (PTHREAD_MUTEX_DEFAULT): スレッドがすでにロックされているデフォルト ロックを再度ロックするか、別のスレッドによってロックされているデフォルト ロックをアンロックするか、ロックされていないデフォルト ロックをアンロックすると、予期せぬ結果が生じる可能性があるため、このロックは実装時に上記の 3 つのロックのいずれかにマップされる可能性があります。
関連メソッド:
// 静态方式创建互斥锁 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 动态方式创建互斥锁,其中参数mutexattr用于指定互斥锁的类型,具体类型见上面四种,如果为NULL,就是普通锁。 int pthread_mutex_init (pthread_mutex_t* mutex,const pthread_mutexattr_t* mutexattr); int pthread_mutex_lock(pthread_mutex_t *mutex); // 加锁,阻塞 int pthread_mutex_trylock(pthread_mutex_t *mutex); // 尝试加锁,非阻塞 int pthread_mutex_unlock(pthread_mutex_t *mutex); // 解锁
例:
#include<stdio.h> #include<pthread.h> int ticket_num=10000000; pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; void *sell_ticket(void *arg) { while(ticket_num>0) { pthread_mutex_lock(&mutex); if(ticket_num>0) { ticket_num--; } pthread_mutex_unlock(&mutex); } } int main() { pthread_t t1,t2,t3; pthread_create(&t1, NULL, &sell_ticket, NULL); pthread_create(&t2, NULL, &sell_ticket, NULL); pthread_create(&t3, NULL, &sell_ticket, NULL); pthread_join(t1, NULL); pthread_join(t2, NULL); pthread_join(t3, NULL); printf("ticket_num=%d\n", ticket_num); return 0; }
2. スピン ロック
Spin As名前が示すように、ロックは無限ループであり、常にポーリングを行っています。スレッドがスピン ロックを取得できない場合、ミューテックス ロックのようにブロッキング スリープ状態にはなりませんが、ロックを取得するために継続的にポーリングを続けます。スピン ロックがすぐに解放されると、パフォーマンスは非常に高くなりますが、スピン ロックが長時間解放されない場合、または内部で大量の IO ブロックが存在する場合は、ロックを取得している他のスレッドがポーリングすることになります。継続的に CPU 使用率 (具体的には CPU 時間) が 100% に達します。
関連メソッド:
int pthread_spin_init(pthread_spinlock_t *lock, int pshared); // 创建自旋锁 int pthread_spin_lock(pthread_spinlock_t *lock); // 加锁,阻塞 int pthread_spin_trylock(pthread_spinlock_t *lock); // 尝试加锁,非阻塞 int pthread_spin_unlock(pthread_spinlock_t *lock); // 解锁
例:
#include<stdio.h> #include<pthread.h> int ticket_num=10000000; pthread_spinlock_t spinlock; void *sell_ticket(void *arg) { while(ticket_num>0) { pthread_spin_lock(&spinlock); if(ticket_num>0) { ticket_num--; } pthread_spin_unlock(&spinlock); } } int main() { pthread_spin_init(&spinlock, 0); pthread_t t1,t2,t3; pthread_create(&t1, NULL, &sell_ticket, NULL); pthread_create(&t2, NULL, &sell_ticket, NULL); pthread_create(&t3, NULL, &sell_ticket, NULL); pthread_join(t1, NULL); pthread_join(t2, NULL); pthread_join(t3, NULL); printf("ticket_num=%d\n", ticket_num); return 0; }
3. セマフォ
セマフォは、数値を制御するために使用されるカウンターです。限られた共有リソースにアクセスするスレッドの数。
関連メソッド:
// 创建信号量 // pshared:一般取0,表示调用进程的信号量。非0表示该信号量可以共享内存的方式,为多个进程所共享(Linux暂不支持)。 // value:信号量的初始值,可以并发访问的线程数。 int sem_init (sem_t* sem, int pshared, unsigned int value); int sem_wait (sem_t* sem); // 信号量减1,信号量为0时就会阻塞 int sem_trywait (sem_t* sem); // 信号量减1,信号量为0时返回-1,不阻塞 int sem_timedwait (sem_t* sem, const struct timespec* abs_timeout); // 信号量减1,信号量为0时阻塞,直到abs_timeout超时返回-1 int sem_post (sem_t* sem); // 信号量加1
例:
#include<stdio.h> #include<pthread.h> #include <semaphore.h> int ticket_num=10000000; sem_t sem; void *sell_ticket(void *arg) { while(ticket_num>0) { sem_wait(&sem); if(ticket_num>0) { ticket_num--; } sem_post(&sem); } } int main() { sem_init(&sem, 0, 1); // value=1表示最多1个线程同时访问共享资源,与互斥量等价 pthread_t t1,t2,t3; pthread_create(&t1, NULL, &sell_ticket, NULL); pthread_create(&t2, NULL, &sell_ticket, NULL); pthread_create(&t3, NULL, &sell_ticket, NULL); pthread_join(t1, NULL); pthread_join(t2, NULL); pthread_join(t3, NULL); printf("ticket_num=%d\n", ticket_num); return 0; }
4. 条件変数
条件変数を使用すると、呼び出し元のスレッドが実行されます。条件が満たされた場合はブロックされ、条件が満たされない場合は起動を待ちます。ミューテックス ロックと組み合わせて使用する必要があります。
条件変数は、プロデューサー モデルとコンシューマー モデルでよく使用されます。
関連メソッド:
pthread_cond_t cond=PTHREAD_COND_INITIALIZER; // 创建条件变量,一个互斥锁可以对应多个条件变量 int pthread_cond_wait (pthread_cond_t* cond,pthread_mutex_t* mutex); // 阻塞等待条件满足,同时释放互斥锁mutex int pthread_cond_timedwait (pthread_cond_t* cond, pthread_mutex_t* mutex, const struct timespec* abstime); // 带超时的阻塞等待条件满足,同时释放互斥锁mutex // 从条件变量cond中唤出一个线程,令其重新获得原先的互斥锁 // 被唤出的线程此刻将从pthread_cond_wait函数中返回,但如果该线程无法获得原先的锁,则会继续阻塞在加锁上。 int pthread_cond_signal (pthread_cond_t* cond); // 从条件变量cond中唤出所有线程 int pthread_cond_broadcast (pthread_cond_t* cond);
例:
#include<stdio.h> #include<pthread.h> int max_buffer=10; int count=0; pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; pthread_cond_t notempty=PTHREAD_COND_INITIALIZER; pthread_cond_t notfull=PTHREAD_COND_INITIALIZER; void *produce(void *args) { while(1) { pthread_mutex_lock(&mutex); while(count == max_buffer) { printf("buffer is full, wait...\n"); pthread_cond_wait(¬full, &mutex); } printf("produce ...\n"); count++; sleep(1); pthread_cond_signal(¬empty); pthread_mutex_unlock(&mutex); } } void *consumer(void *args) { while(1) { pthread_mutex_lock(&mutex); while(count == 0) { printf("buffer is empty, wait...\n"); pthread_cond_wait(¬empty, &mutex); } printf("consumer ...\n"); count--; sleep(1); pthread_cond_signal(¬full); pthread_mutex_unlock(&mutex); } } int main() { pthread_t t1,t2,t3,t4; pthread_create(&t1, NULL, &produce, NULL); pthread_create(&t2, NULL, &produce, NULL); pthread_create(&t3, NULL, &consumer, NULL); pthread_create(&t4, NULL, &consumer, NULL); pthread_join(t1, NULL); return 0; }
5、读写锁
读写锁可以有三种状态:读模式下加锁状态,写模式下加锁状态,不加锁状态。一次只有一个线程可以占有写模式的读写锁,但是多个线程可以同时占有读模式的读写锁。读写锁也叫做共享-独占锁,当读写锁以读模式锁住时,它是以共享模式锁住的,当它以写模式锁住时,它是以独占模式锁住的,读读共享,读写互斥。
相关方法:
// 创建读写锁 pthread_rwlock_t rwlock=PTHREAD_RWLOCK_INITIALIZER; int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); // 加读锁,阻塞 int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); // 加写锁,阻塞 int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); // 释放读锁或者写锁 int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); // 尝试加读锁,非阻塞 int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); // 尝试加写锁,非阻塞
例子:
#include <stdio.h> #include <pthread.h> pthread_rwlock_t rwlock=PTHREAD_RWLOCK_INITIALIZER; void *read(void *arg) { while(1) { pthread_rwlock_rdlock(&rwlock); rintf("read message.\n"); sleep(1); pthread_rwlock_unlock(&rwlock); sleep(1); } } void *write(void *arg) { while(1) { pthread_rwlock_wrlock(&rwlock); printf("write message.\n"); sleep(1); pthread_rwlock_unlock(&rwlock); sleep(1); } } int main(int argc,char *argv[]) { pthread_t t1,t2,t3; pthread_create(&t1, NULL, &read, NULL); pthread_create(&t2, NULL, &read, NULL); pthread_create(&t3, NULL, &write, NULL); pthread_join(t1, NULL); return 0; }
6、屏障
屏障(barrier)是用户协调多个线程并行工作的同步机制。屏障允许每个线程等待,直到所有的合作线程都到达某一点,然后所有线程都从该点继续执行。pthread_join函数就是一种屏障,允许一个线程等待,直到另一个线程退出。但屏障对象的概念更广,允许任意数量的线程等待,直到所有的线程完成处理工作,而线程不需要退出,当所有的线程达到屏障后可以接着工作。
相关方法:
// 创建屏障 int pthread_barrier_init(pthread_barrier_t *barrier,const pthread_barrrierattr_t *attr,unsigned int count) // 阻塞等待,直到所有线程都到达 int pthread_barrier_wait(pthread_barrier_t *barrier)
例子:
#include <stdio.h> #include <pthread.h> pthread_barrier_t barrier; void *go(void *arg){ sleep (rand () % 10); printf("%lu is arrived.\n", pthread_self()); pthread_barrier_wait(&barrier); printf("%lu go shopping...\n", pthread_self()); } int main() { pthread_barrier_init(&barrier, NULL, 3); pthread_t t1,t2,t3; pthread_create(&t1, NULL, &go, NULL); pthread_create(&t2, NULL, &go, NULL); pthread_create(&t3, NULL, &go, NULL); pthread_join(t1, NULL); return 0; }
相关推荐:《Linux视频教程》
以上がLinux でのマルチスレッド同期にはどのような方法がありますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undress AI Tool
脱衣画像を無料で

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

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

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

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

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

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

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

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

Google Chromeにファイルをアップロードするのに問題がありますか?これは迷惑かもしれませんよね?電子メールにドキュメントを添付したり、ソーシャルメディアで画像を共有したり、仕事や学校の重要なファイルを送信したりするかどうかにかかわらず、スムーズなファイルのアップロードプロセスが重要です。したがって、Windows PCのChromeでファイルのアップロードが引き続き失敗している場合、イライラする可能性があります。お気に入りのブラウザを放棄する準備ができていない場合は、Windows Google Chrome 1にファイルをアップロードできない修正のヒントをいくつか紹介します。高度なトラブルシューティングのヒントについて学ぶ前に、ユニバーサル修理から始めて、以下に説明する基本的なソリューションを試すのが最善です。インターネット接続の問題のトラブルシューティング:インターネット接続

Linuxユーザーグループを管理するには、表示、作成、削除、変更、およびユーザー属性の調整の操作をマスターする必要があります。ユーザーグループ情報を表示するには、cat/etc/groupまたはgetentgroupを使用して、グループ[username]またはid [username]を使用して、ユーザーが属するグループを表示できます。 GroupAddを使用してGroupを作成し、GroupDelを使用してGIDを指定します。 GroupDelを使用して、空のグループを削除します。 USERMOD-AGを使用してユーザーをグループに追加し、USERMOD-Gを使用してメイングループを変更します。 USERMOD-Gを使用して、 /etc /groupを編集するか、VIGRコマンドを使用してグループからユーザーを削除します。 GroupMod-N(名前を変更)またはGroupMod-G(GIDの変更)を使用してグループプロパティを変更し、関連するファイルの許可を更新することを忘れないでください。

Sudoは「SollideSerdo」または「Superuserdo」の略で、ユーザーが他のユーザー(通常はroot)の許可を使用してコマンドを実行できるようにします。そのコアの使用には、次のものが含まれます。1。ソフトウェアのインストールやシステムファイルの編集など、システムレベルの操作を実行します。 2。保護されたディレクトリまたはログへのアクセス。 3。nginxの再起動などのサービスを管理します。 4. /etc /hostsなどのグローバル設定を変更します。使用すると、システムは /etc /sudoers構成をチェックし、ユーザーパスワードを確認し、rootとして継続的にログインする代わりに一時的なアクセス許可を提供し、セキュリティを確保します。ベストプラクティスには、必要な場合にのみ、ネットワークコマンドの盲目的に実行され、visudoを使用したSudoersファイルの編集、継続的な操作を検討してください。

Linux Systemsでは、1。IPAまたはHOSTNAME-Iコマンドを使用してプライベートIPを表示します。 2。CurlifConfig.meまたはcurlipinfo.io/ipを使用して、パブリックIPを取得します。 3.デスクトップバージョンは、システム設定を介してプライベートIPを表示でき、ブラウザは特定のWebサイトにアクセスしてパブリックIPを表示できます。 4.一般的なコマンドは、クイックコールのためにエイリアスとして設定できます。これらの方法はシンプルで実用的で、さまざまなシナリオでのIP表示のニーズに適しています。

linuxcanrunonModesthardwarewithspecificminimumrequirements.a1ghzprocessor(x86orx86_64)が必要であり、 amshouldbeatleast512mbforcommand-lineuseor2gbfordesktopenvironments.diskspacerequiresaminimumof5–10gb、25gbisbetterforad

デジタルの世界の先駆者として、ビットコインのユニークなコード名と基礎となるテクノロジーは、常に人々の注目の焦点でした。その標準コードはBTCであり、国際標準を満たす特定のプラットフォームでXBTとしても知られています。技術的な観点からは、ビットコインは単一のコードスタイルではなく、巨大で洗練されたオープンソースソフトウェアプロジェクトです。そのコアコードは主にCで記述されており、暗号化、分散システム、経済学の原則が組み込まれているため、誰でもコードを表示、レビュー、貢献できます。

Linux/MacOSのシャットダウンコマンドは、パラメーターを介してシャットダウン、再起動、およびタイミング操作を行うことができます。 1.すぐにマシンをオフにし、sudoshutdownnowまたは-h/-pパラメーターを使用します。 2。シャットダウンに時間または特定の時点を使用して、-cの使用をキャンセルします。 3. -Rパラメーターを使用して再起動し、タイミングの再開をサポートします。 4. SUDO許可の必要性に注意し、リモート操作に注意し、データの損失を避けてください。

PHPコンテナが自動構造をサポートできるようにするために、コアは連続統合(CI)プロセスの構成にあります。 1. DockerFileを使用して、基本的な画像、拡張インストール、依存関係管理、許可設定など、PHP環境を定義します。 2. GitlabciなどのCI/CDツールを構成し、.gitlab-ci.ymlファイルを介してビルド、テスト、展開段階を定義して、自動構造、テスト、展開を実現します。 3. phpunitなどのテストフレームワークを統合して、コードの変更後にテストが自動的に実行されることを確認します。 4. Kubernetesなどの自動展開戦略を使用して、deployment.yamlファイルを介して展開構成を定義します。 5. DockerFileを最適化し、マルチステージ構造を採用します
