目次
1.2 ミューテックスロックの初期化: pthread_mutex_init 関数
1.3 ミューテックスロック: pthread_mutex_lock 関数
1.4 ミューテックスのロック解除: pthread_mutex_unlock 関数
1.5 ミューテックスロックの破棄: pthread_mutex_destroy 関数
2.5 セマフォのカウント値を取得する: sem_getvalue 関数
0. ミューテックスロックとセマフォ
同期ミューテックスの概要
マルチタスク オペレーティング システムでは、同時に実行される複数のタスクが同じリソースにアクセスしたり、同じリソースを使用したりする必要がある場合があります。複数のタスク間には依存関係があり、あるタスクの動作は別のタスクに依存します。
同期と相互排他は、これら 2 つの問題を解決するために使用されます。
相互に排他的:
パブリック リソースは一度に 1 つのプロセスまたはスレッドのみが使用でき、複数のプロセスまたはスレッドが同時にパブリック リソースを使用することはできません。POSIX 標準には、プロセスとスレッドの同期と相互排他のための 2 つの主な方法、セマフォとミューテックス ロックがあります。
同期:
2 つ以上のプロセスまたはスレッドは動作中に同期し、あらかじめ決められた順序で実行されます。
同期は相互排他に基づいた順序です。
1. ミューテックスロック
1.1 ミューテックスロックの概念
Mutex は、共有リソースへのアクセスを制御するための単純なロック方法であり、Mutex にはロックとロック解除の 2 つの状態しかありません。このリソースにアクセスする前に、まずミューテックスを申請する必要があります。
- ミューテックスがロック解除状態にある場合、ミューテックスはすぐに適用され、ロックされます。
- ミューテックスがロック状態にある場合、申請者はデフォルトでブロックされます。開錠操作はロッカー側で行ってください。
ミューテックス ロックを初期化します: pthread_mutex_init 関数。
ミューテックスは pthread_mutex_t データ型で表され、ミューテックス ロックを使用する前に初期化する必要があります。
静的に割り当てられたミューテックス ロック:
pthread_mutex_t ミューテックス = PTHREAD_MUTEX_INITIALIZER;
ミューテックス ロックを動的に割り当てます。
pthread_mutex_t ミューテックス;
ミューテックス ロックを破棄します: pthread_mutex_destroy
1.2 ミューテックスロックの初期化: pthread_mutex_init 関数
pthread_mutex_init 関数:
#include<pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
関数:
ミューテックスロックを初期化します。
パラメータ:
mutext: ミューテックス ロックのアドレス。
attr: ミューテックス ロックの属性。デフォルトの属性は NULL です。
戻り値:
成功: 0
失敗: 非 0
1.3 ミューテックスロック: pthread_mutex_lock 関数
pthread_mutex_lock 関数
#include<pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
関数:
ミューテックスをロックします。既にロックされている場合、ミューテックスのロックが解除されるまで呼び出し元はブロックされます。
パラメータ:
mutex: 指定されたミューテックス ロック。
戻り値:
成功: 0
失敗: 非 0
#include<pthread.h>
int pthread_mutex_trylock(pthread_mutex_t * mutex);
関数:
ミューテックスをロックします。すでにロックされている場合、ロックは失敗し、関数はすぐに戻ります。
パラメータ:
mutex: ミューテックス ロック アドレス。
戻り値:
成功: 0
失敗: 非 0
1.4 ミューテックスのロック解除: pthread_mutex_unlock 関数
pthread_mutex_unlock 関数
#include<pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
関数:
指定されたミューテックスのロックを解除します。
パラメータ:
mutex: ミューテックス ロック アドレス。
戻り値:
成功: 0
失敗: 非 0
1.5 ミューテックスロックの破棄: pthread_mutex_destroy 関数
pthread_mutex_destroy 関数
#include<pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
関数:
指定されたミューテックス ロックを破棄します。
パラメータ:
mutex: ミューテックス ロック アドレス。
戻り値:
成功: 0
失敗: 非 0
1.6 ミューテックスロックの場合
1.61 ミューテックスロックを使用しない場合の結果
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
int money = 10000;
void* pthread_fun1(void* arg)
{
int get, yu, shiji;
get = 10000;
printf("zhangsan look balance\n");
sleep(1);
yu = money;
printf("zhangsan spent money\n");
sleep(1);
if (get > yu)
{
shiji = 0;
}
else
{
shiji = get;
yu = yu - get;
money = yu;
}
printf("zhangsan want spent %d, fact spent is %d, balance is %d\n", get, shiji, yu);
pthread_exit(NULL);
}
void* pthread_fun2(void* arg)
{
int get, yu, shiji;
get = 10000;
printf("lisi look balance\n");
sleep(1);
yu = money;
printf("lisi spent money\n");
sleep(1);
if (get > yu)
{
shiji = 0;
}
else
{
shiji = get;
yu = yu - get;
money = yu;
}
printf("lisi want spent %d, fact spent is %d, balance is %d\n", get, shiji, yu);
pthread_exit(NULL);
}
int main()
{
pthread_t thread1, thread2;
if (pthread_create(&thread1, NULL, pthread_fun1, NULL) != 0)
{
perror("fail to pthread_create");
exit(1);
}
if (pthread_create(&thread2, NULL, pthread_fun2, NULL) != 0)
{
perror("fail to pthread_creat");
exit(1);
}
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
実行のスクリーンショット:
1.62 ミューテックスロックを使用した結果
コード例:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
int money = 10000;
//第一步:创建互斥锁
pthread_mutex_t mutex;
void* pthread_fun1(void* arg)
{
int get, yu, shiji;
get = 10000;
//第三步,互斥锁上锁
pthread_mutex_lock(&mutex);
printf("zhangsan look balance\n");
sleep(1);
yu = money;
printf("zhangsan spent money\n");
sleep(1);
if (get > yu)
{
shiji = 0;
}
else
{
shiji = get;
yu = yu - get;
money = yu;
}
printf("zhangsan want spent %d, fact spent is %d, balance is %d\n", get, shiji, yu);
//第四步,互斥锁解锁
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
void* pthread_fun2(void* arg)
{
int get, yu, shiji;
get = 10000;
//第三步,互斥锁上锁
pthread_mutex_lock(&mutex);
printf("lisi look balance\n");
sleep(1);
yu = money;
printf("lisi spent money\n");
sleep(1);
if (get > yu)
{
shiji = 0;
}
else
{
shiji = get;
yu = yu - get;
money = yu;
}
printf("lisi want spent %d, fact spent is %d, balance is %d\n", get, shiji, yu);
//第四步,互斥锁解锁
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
int main()
{
//第二步,初始化互斥锁
pthread_mutex_init(&mutex, NULL);
pthread_t thread1, thread2;
if (pthread_create(&thread1, NULL, pthread_fun1, NULL) != 0)
{
perror("fail to pthread_create");
exit(1);
}
if (pthread_create(&thread2, NULL, pthread_fun2, NULL) != 0)
{
perror("fail to pthread_creat");
exit(1);
}
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
//第五步,销毁互斥锁
pthread_mutex_destroy(&mutex);
return 0;
}
結果:
2. 信号量
2.1 セマフォの概念
セマフォは、プロセスまたはスレッド間の同期と相互排除に広く使用されており、本質的には非負の整数カウンターであり、パブリック リソースへのアクセスを制御するために使用されます。
プログラミング時には、セマフォの値を操作した結果からパブリックリソースへのアクセス権限があるかどうかを判断することができ、セマフォの値が0より大きい場合はアクセス可能、それ以外の場合はブロックされます。
セマフォは PV 操作とも呼ばれます。PV はセマフォに対する操作です。P 操作はセマフォ sem を 1 減らし、V 操作はセマフォを sem+1 にします。P 操作の場合、セマフォの sem 値が 0 以下の場合、P 操作はブロックされます。セマフォの値が 0 より大きい場合、P 操作を実行して 1 を減算できます。
セマフォは主に、プロセスまたはスレッド間の同期と相互排他という 2 つの典型的な状況で使用されます。
- 相互排除に使用される場合、多くの場合、複数のプロセス (またはスレッド) は 1 つのセマフォのみを設定します。
- 同期操作に使用される場合、多くの場合、複数のセマフォが設定され、それらの間の実行シーケンスを実現するために異なる初期値が配置されます。
セマフォは相互排除に使用されます。
セマフォは同期に使用されます。
2.2 セマフォの初期化:sem_init関数
sem_init 関数
#include<セマフォ.h>
int sem_init(sem_t *sem、int pshared、unsigned int 値);
関数:
セマフォを作成し、その値を初期化します。
パラメータ:
sem: セマフォのアドレス。
pshared: 0 に等しい場合、セマフォはスレッド間で共有されます; 0 に等しくない場合、セマフォはプロセス間で共有されます。
value: セマフォの初期値。
戻り値:
成功: 0
失敗: -1
2.3 セマフォのP動作:sem_wait関数
sem_wait 関数
#include<セマフォ.h>
int sem_wait(sem_t *sem);
関数:
セマフォの値を 1 ずつ減らします。セマフォの値が 0 以下の場合、この関数により呼び出し元はブロックされます。
パラメータ:
sem: セマフォのアドレス。
戻り値:
成功: 0
失敗: -1
#include<セマフォ.h>
int sem_trywait(sem_t *sem);
関数:
セマフォの値を 1 ずつ減らします。セマフォの値が 0 より小さい場合、セマフォに対する操作は失敗し、関数はすぐに戻ります。
パラメータ:
sem: セマフォアドレス。
戻り値:
成功: 0
失敗: -1
セマフォの2.4V動作:sem_post関数
sem_post関数
#include<セマフォ.h>
int sem_post(sem_t *sem);
関数:
セマフォの値を 1 増やして、待機中のスレッドをウェイクアップする信号を送信します。
パラメータ:
sem: セマフォアドレス。
戻り値:
成功: 0
失敗: -1
2.5 セマフォのカウント値を取得する: sem_getvalue 関数
sem_getvalue関数
#include<セマフォ.h>
int sem_getvalue(sem_t *sem, int *sval);
関数:
sem で識別されたセマフォの値を取得し、sval に保存します。
パラメータ:
sem: セマフォアドレス。
sval: セマフォ値が保存されるアドレス。
戻り値:
成功: 0
失敗: -1
2.6 セマフォの破棄:sem_destroy関数
sem_destroy関数
#include<セマフォ.h>
int sem_destroy(sem_t *sem);
関数:
sem で識別されたセマフォを削除します。
パラメータ:
sem: セマフォアドレス。
戻り値:
成功: 0
失敗: -1
2.7 セマフォの使用
2.7.1 セマフォによる相互排他機能の実装
コード例:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
//第一步,创建信号量
sem_t sem;
void printer(char* str)
{
//第三步,P操作
sem_wait(&sem);
while (*str)
{
putchar(*str);
fflush(stdout);
str++;
sleep(1);
}
//第四步,V操作
sem_post(&sem);
}
void* thread_fun1(void* arg)
{
char* str1 = "hello";
printer(str1);
}
void* thread_fun2(void* arg)
{
char* str2 = "world";
printer(str2);
}
int main()
{
//第二步,初始化信号量
sem_init(&sem, 0, 1);
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, thread_fun1, NULL);
pthread_create(&tid2, NULL, thread_fun2, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
printf("\n");
//第五步,销毁信号量
sem_destroy(&sem);
return 0;
}
実行のスクリーンショット:
2.7.2 同期機能を実現するセマフォ
コード例:
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
char ch = 'a';
//第一步,创建两个信号量
sem_t sem_g, sem_p;
void* pthread_g(void* arg)
{
while (ch <= 'z')
{
//第四步,后执行线程
sem_wait(&sem_g);
ch++;
sleep(1);
//第六步,V操作
sem_post(&sem_p);
}
}
void* pthread_p(void* arg)
{
while (ch < 'z')
{
//第三步,先执行线程
sem_wait(&sem_p);
printf("%c", ch);
fflush(stdout);
//第五步,V操作
sem_post(&sem_g);
}
}
int main()
{
//第二步,初始化信号量
sem_init(&sem_g, 0, 0);
sem_init(&sem_p, 0, 1);
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, pthread_g, NULL);
pthread_create(&tid2, NULL, pthread_p, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
printf("\n");
//第七步,销毁信号量
sem_destroy(&sem_g);
sem_destroy(&sem_p);
return 0;
}
実行のスクリーンショット:
要約:
一般に、ミューテックスとセマフォは、スレッドとプロセスの同期のための重要なツールです。ミューテックス ロックは主にリソースを保護し、同時に 1 つのスレッドまたはプロセスのみが特定のリソースにアクセスできるようにして、同時実行の問題を回避するために使用されます。セマフォは、スレッドとプロセス間の通信と同期によく使用され、一定の範囲内で同時アクセスを制御し、プログラムに対してより詳細な同時実行制御を提供します。
ミューテックスとセマフォの使用法と違いをマスターすると、マルチスレッドおよびマルチプロセス プログラミングの効率と安定性を大幅に向上させることができます。