Linuxシステムプログラミング55スレッド-相互排他ロックの分析

ミューテックスを紹介します:

スレッド間の競合の失敗:

実験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);
	
}

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/LinuxArmbiggod/article/details/114264585