Linux system programming 55 threads-analysis of mutual exclusion locks

Introduce mutex:

Competition failure between threads:

Experiment 1: Competition failure between threads, use sleep() to amplify competition failure

#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);
	
}

Because it is a single-core virtual machine, the effect of multi-core cannot be simulated, so sleep(1) in thr_add() for one second is compared to scheduling other threads by the scheduler, amplifying the competition between each thread, looking at the results, and creating it. All of the 20 threads received the FNAME file, and the value they got was 1. After sleep(), they started to add a write value, resulting in repeated writes of 2 values ​​to the file 20 times.

The reason for this problem is caused by competition between threads.


Mutex:

Insert picture description here

The red lined sentence is too important! ! ! After the mutex is locked, any other thread that tries to lock the mutex again will be blocked until the current thread releases the mutex,
even if it wants to hold the lock again without unlocking it. Blocked! ! !

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;

Lock and unlock the mutex:

Insert picture description here

NAME
pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock — lock and unlock a mutex

SYNOPSIS
#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); 

Misunderstanding:
Don't directly understand that as long as there is a pthread_mutex_lock() statement, the following code is a critical section, so it is easy to be confused. But it should be understood as: only I want to get the lock, then when other threads want the lock, they can't get the lock and will block. Use this rule to create the critical zone we need.

Experiment 2: Modify the above experiment to ensure that the code that can only be done by one person at the same time is the critical section.

#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$ 

Experiment 3, mutual exclusion, deepen your understanding: the four threads continuously output a, b, c, d to the terminal in sequence within the specified time, and each thread outputs a letter

Create four mutexes, four threads, in the critical section code, each thread is responsible for holding the lock, outputting, and releasing the lock of the next thread. In this way, each thread can poll the lock output.

#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);
	
}

Insert picture description here

Guess you like

Origin blog.csdn.net/LinuxArmbiggod/article/details/114264585