ミューテックスを紹介します:
スレッド間の競合の失敗:
実験1:スレッド間の競合の失敗、sleep()を使用して競合の失敗を増幅する
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#define THRNUM 20
#define FNAME "/home/mhr/Desktop/xitongbiancheng/parallel/thread/posix/out"
#define LINESIZE 1024 //提前写好1
static void *thr_add(void *p)
{
FILE *fp;
char linebuf[LINESIZE];
fp = fopen(FNAME,"r+");
if(fp == NULL)
{
perror("fopen()");
exit(1);
}
fgets(linebuf,LINESIZE,fp);
fseek(fp,0,SEEK_SET);
sleep(1);
fprintf(fp,"%d\n",atoi(linebuf)+1);
fclose(fp);
pthread_exit(NULL);
}
int main()
{
pthread_t tid[THRNUM];
int i,err;
for(i = 0; i < THRNUM; i++)
{
err = pthread_create(tid+i,NULL,thr_add,NULL);
if(err)
{
fprintf(stderr,"pthread_create(): %s\n",strerror(err));
exit(1);
}
}
for(i = 0;i < THRNUM; i++)
{
pthread_join(tid[i],NULL);
}
exit(0);
}
これは仮想マシンのシングルコアであるため、マルチコアの効果をシミュレートできません。したがって、thr_add()のsleep(1)を1秒間、スケジューラーによる他のスレッドのスケジュールと比較して、各スレッド間の競合を増幅します。結果を見ると、作成されていることがわかります。20個のスレッドすべてがFNAMEファイルを受信し、取得した値は1でした。sleep()の後、書き込み値の追加を開始し、2の書き込みが繰り返されました。ファイルへの値を20回。
この問題の理由は、スレッド間の競合が原因です。
ミューテックス:
赤い線の文は重要すぎます!!!ミューテックスがロックされた後、ミューテックスを再度ロックしようとする他のスレッドは
、ロックを解除せずに再びロックを保持したい場合でも、現在のスレッドがミューテックスを解放するまでブロックされます。!!
NAME
pthread_mutex_destroy, pthread_mutex_init — destroy and initialize a mutex,初始化和销毁 一个 互斥量
SYNOPSIS
#include <pthread.h>
SYNOPSIS
#include <pthread.h>
//销毁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
//动态初始化
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
//静态初始化方式
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
ミューテックスをロックおよびロック解除します。
名前
pthread_mutex_lock、pthread_mutex_trylock、pthread_mutex_unlock —ミューテックスをロックおよびロック解除します
書式
の#include <pthread.hの>
//以阻塞的方式 限制住某段代码的执行
int pthread_mutex_lock(pthread_mutex_t *mutex);
//以非阻塞的方式 限制住某段代码的执行
int pthread_mutex_trylock(pthread_mutex_t *mutex);
//解锁
int pthread_mutex_unlock(pthread_mutex_t *mutex);
誤解:
pthread_mutex_lock()ステートメントがある限り、次のコードはクリティカルセクションであるため、混乱しやすいことを直接理解しないでください。しかし、それは次のように理解されるべきです:私だけがロックを取得したいのですが、他のスレッドがロックを必要とするとき、彼らはロックを取得できず、ブロックします。このルールを使用して、必要なクリティカルゾーンを作成します。
実験2:上記の実験を変更して、同時に1人だけが実行できるコードがクリティカルセクションになるようにします。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#define THRNUM 20
#define FNAME "/home/mhr/Desktop/xitongbiancheng/parallel/thread/posix/out"
#define LINESIZE 1024
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static void *thr_add(void *p)
{
FILE *fp;
char linebuf[LINESIZE];
fp = fopen(FNAME,"r+");
if(fp == NULL)
{
perror("fopen()");
exit(1);
}
pthread_mutex_lock(&mut); //上锁
fgets(linebuf,LINESIZE,fp);
fseek(fp,0,SEEK_SET);
//sleep(1);
fprintf(fp,"%d\n",atoi(linebuf)+1); // 全缓冲,需要fflush 或者 fclose 刷新 才能写到目标文件
fclose(fp);// fprintf(fp 全缓冲,需要fflush 或者 fclose 刷新 才能写到目标文件,所以也在临界区
pthread_mutex_unlock(&mut); //解锁
pthread_exit(NULL);
}
int main()
{
pthread_t tid[THRNUM];
int i,err;
for(i = 0; i < THRNUM; i++)
{
err = pthread_create(tid+i,NULL,thr_add,NULL);
if(err)
{
fprintf(stderr,"pthread_create(): %s\n",strerror(err));
exit(1);
}
}
for(i = 0;i < THRNUM; i++)
{
pthread_join(tid[i],NULL);
}
pthread_mutex_destroy(&mut);
exit(0);
}
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ gcc add.c -lpthread
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ cat out
1
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ ./a.out
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ cat out
21
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ ./a.out
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ cat out
41
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ ./a.out
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$ cat out
61
mhr@ubuntu:~/Desktop/xitongbiancheng/parallel/thread/posix$
実験3、相互排除、理解を深める:4つのスレッドが指定された時間内にa、b、c、dを順番に端末に連続的に出力し、各スレッドが文字を出力します
クリティカルセクションコードで4つのミューテックス、4つのスレッドを作成します。各スレッドは、ロックの保持、出力、および次のスレッドのロックの解放を担当します。このようにして、各スレッドはロック出力をポーリングできます。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#define THRNUM 4
static pthread_mutex_t mut[THRNUM];
static int next(int n)
{
if(n+1 == THRNUM)
return 0;
return n+1;
}
static void *thr_add(void *p)
{
int n = (int)p;
int c = 'a' + (int)p;
while(1)
{
pthread_mutex_lock(mut+n);
write(1,&c,1);
pthread_mutex_unlock(mut+next(n));//这里会执行 被阻塞的目标线程,当前线程由于没有释放自己持有的锁,会被再次阻塞。
}
pthread_exit(NULL);
}
int main()
{
pthread_t tid[THRNUM];
int i,err;
for(i = 0; i < THRNUM; i++)
{
pthread_mutex_init(mut+i,NULL);
pthread_mutex_lock(mut+i);
err = pthread_create(tid+i,NULL,thr_add,(void *)i);
if(err)
{
fprintf(stderr,"pthread_create(): %s\n",strerror(err));
exit(1);
}
}
pthread_mutex_unlock(mut+0);//释放线程1的锁
alarm(5);
for(i = 0;i < THRNUM; i++)
{
pthread_join(tid[i],NULL);
}
exit(0);
}