Thread learning (producer consumer problem & philosopher eating problem)

The concept of threads:

concept:

Process: From the perspective of operating system core, process is the basic unit of operating system scheduling and allocating memory resources and CPU time slices. It provides a running environment for running applications. In simple terms, a process is a running activity of an application.

Thread: Thread is a sequential code flow inside the program, it is the most basic unit of CPU scheduling resources.

relationship:

(1) A thread cannot be executed independently. It must be attached to a running application (ie a process). The process contains at least one thread and can contain multiple threads, and a thread can only be attached to one process;

(2) The process is the entity of operating system resource management, and the thread is the entity of the process.

the difference:

When the operating system allocates process resources, multiple threads belonging to the same process can share the memory resources in the process with each other. The reason is that the thread does not have its own independent memory resources, it has only its own execution stack and local variables. Among multiple processes, each process has its own set of variables, that is, each process has an independent memory unit. This makes the communication between multiple threads easier and more efficient than the communication between multiple processes.

Producer consumer issues:

Problem Description:

The producer-consumer problem, also known as the limited buffer problem, is a classic case of multithreaded synchronization problems. This problem describes what happens when two threads sharing a fixed-size buffer-the so-called "producer" and "consumer"-actually run. The main role of the producer is to generate a certain amount of data into the buffer, and then repeat the process. At the same time, consumers are consuming these data in the buffer. The key to this problem is to ensure that producers will not add data when the buffer is full, and consumers will not consume data when the buffer is empty.

problem analysis:

1. When the buffer is empty, the consumer can no longer consume
. 2. When the buffer is full, the producer can no longer produce
. 3. When one thread is producing or consuming, the other threads can no longer produce or consume, etc. Operation, that is to maintain synchronization between threads
4. Pay attention to the order of condition variables and mutex locks

Code display:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>

#define N 2//消费者或生产者的数目
#define M 10//缓冲数目

int in=0;//生产者放置产品的位置
int out=0;//消费者读取产品的位置
int buff[M]={
    
    0};//缓冲初始化为0,开始时并没有产品
sem_t empty_sem;//同步信号量,当满了时阻止生产者放产品
sem_t full_sem;//同步信号量,当没产品时阻止消费者消费
pthread_mutex_t mutex;//互斥信号量,保证一次只有一个线程访问缓冲
int product_id=0;//生产者id
int consume_id=0;//消费者id
//打印缓冲内容
void print()
{
    
    
	int i;
	for(i=0;i<M;i++){
    
    
		printf("%d",buff[i]);
		printf("\n");
	}
}
//生产者方法
void *product()
{
    
    
	int id=++product_id;

	while(1){
    
    
		sleep(1);

		sem_wait(&empty_sem);
		pthread_mutex_lock(&mutex);

		in=in%M;
		printf("product %d in %d.like:\n",id,in);

		buff[in]=1;
		print();
		in++;

		pthread_mutex_unlock(&mutex);
		sem_post(&full_sem);
	}
}
//消费者方法
void *consume()
{
    
    
	int id=++consume_id;
	while(1){
    
    
		sleep(1);

		sem_wait(&full_sem);
		pthread_mutex_lock(&mutex);

		out=out%M;
		printf("consume %d in %d.like:\n",id,out);

		buff[out]=0;
		print();
		out++;

		pthread_mutex_unlock(&mutex);
		sem_post(&empty_sem);
	}
}

int main(int argc,char **argv)
{
    
    
	pthread_t id1[N];
	pthread_t id2[N];
	int i;
	//初始化同步信号量,及初始化互斥信号量
	int ini1=sem_init(&empty_sem,0,M);
	int ini2=sem_init(&full_sem,0,0);
	int ini3=pthread_mutex_init(&mutex,NULL);
	//创建生产者线程
	for(i=0;i<N;i++){
    
    
		pthread_create(&id1[i],NULL,product,(void*)(&i));
	}
	//创建消费者线程
	for(i=0;i<N;i++){
    
    
		pthread_create(&id2[i],NULL,consume,NULL);
	}
	//挂起线程
	for(i=0;i<N;i++){
    
    
		pthread_join(id1[i],NULL);
		pthread_join(id2[i],NULL);
	}
	//销毁信号量
	sem_destroy(&empty_sem);
	sem_destroy(&full_sem);
	//销毁互斥锁
	pthread_mutex_destroy(&mutex);
}

Philosopher’s meal problem:

Problem Description:

There are five philosophers whose way of life is to think and eat alternately. They share a round table and sit on five chairs. There are five bowls and five chopsticks on the round table. A philosopher usually thinks about it. When he is hungry, he tries to use the chopsticks closest to him on the left and right. He can eat only when he has two chopsticks. After eating, put down the chopsticks and continue thinking.

problem analysis:

1. The philosopher can only eat when he has two chopsticks.
2. If the chopsticks have been taken away by someone else, you must wait until the others have finished eating the chopsticks.
3. Any philosopher will not put down the chopsticks he holds before he has two chopsticks to eat.

Problem solution one:

The mutex is used to protect the philosopher's operation of taking the left and right chopsticks before eating, which can prevent deadlocks. (When the i-th philosopher has obtained both left and right chopsticks, other philosophers are allowed to take chopsticks)

Code display:

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<time.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>

#define N 5

sem_t chopsticks[N];//设置5种信号量

pthread_mutex_t mutex;//定义互斥锁

int philosophers[N]={
    
    0,1,2,3,4};//代表5个哲学家的编号

void delay(int len){
    
    //时间缓冲函数
	int i=rand()%len;
	int x;
	while(i>0){
    
    
		x=rand()%len;
		while(x>0){
    
    
			x--;
		}
		i--;
	}
}

void *philosopher(void *arg){
    
    
	int i=*(int *)arg;
	int left=i;//左筷子的编号与哲学家的编号一致
	int right=(i+1)%N;//右筷子的编号为哲学家编号+1
	while(1){
    
    
		printf("哲学家%d正在思考问题\n",i);
		delay(60000);

		printf("哲学家%d饿了\n",i);

		pthread_mutex_lock(&mutex);//加锁

		sem_wait(&chopsticks[left]);//此时这个哲学家左筷子的信号量-1后>=时,表示能继续执行
		printf("哲学家%d拿起了%d号筷子,现在只有一只筷子,不能进餐\n",i,left);
		sem_wait(&chopsticks[right]);
		printf("哲学家%d拿起了%d号筷子\n",i,right);

		pthread_mutex_unlock(&mutex);//解锁

		printf("哲学家%d现在有两只筷子,开始进餐\n",i);
		delay(6000);
		sem_post(&chopsticks[left]);
		printf("哲学家%d放下了号%d筷子\n",i,left);
		sem_post(&chopsticks[right]);
		printf("哲学家%d放下了号%d筷子\n",i,right);
	}
}

int main(int argc,char **argv){
    
    
	int i;
	srand(time(NULL));
	pthread_t philo[N];
	//信号量初始化
	for(i=0;i<N;i++){
    
    
		sem_init(&chopsticks[i],0,1);
	}

	pthread_mutex_init(&mutex,NULL);//互斥锁初始化
	//创建线程
	for(i=0;i<N;i++){
    
    
		pthread_create(&philo[i],NULL,philosopher,&philosophers[i]);
	}
	//挂起线程
	for(i=0;i<N;i++){
    
    
		pthread_join(philo[i],NULL);
	}
	//销毁信号量
	for(i=0;i<N;i++){
    
    
		sem_destroy(&chopsticks[i]);
	}

	pthread_mutex_destroy(&mutex);//销毁互斥锁
}

Problem solution two:

At most, only four philosophers are allowed to take the left chopsticks at the same time, and it is guaranteed that at least one philosopher can eat, and release two chopsticks for others to use after use.

Code display:

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<time.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>

#define N 5

sem_t chopsticks[N];//设置5种信号量
sem_t m;//最多允许有m(4)个哲学家同时拿起左筷子

int philosophers[N]={
    
    0,1,2,3,4};//代表哲学家的5个编号

void delay(int len){
    
    //时间缓冲函数
	int i=rand()%len;
	int x;
	while(i>0){
    
    
		x=rand()%len;
		while(x>0){
    
    
			x--;
		}
		i--;
	}
}

void *philosopher(void *arg){
    
    
	int i=*(int *)arg;
	int left=i;//左筷子的编号与哲学家编号一致
	int right=(i+1)%N;//右筷子的编号为哲学家编号+1
	while(1){
    
    
		printf("哲学家%d正在思考问题\n",i);
		delay(60000);

		printf("哲学家%d饿了\n",i);
		sem_wait(&m);//如果前4个哲学家同时拿起左筷子,则第五个不能拿起左筷子,保证至少有一个哲学家能吃到饭
		sem_wait(&chopsticks[left]);//此时这个哲学家左筷子的信号量-1之后>=0时,表示能继续执行
		printf("哲学家%d拿起了%d号筷子,现在只有一直筷子,不能进餐\n",i,left);
		sem_wait(&chopsticks[right]);
		printf("哲学家%d拿起了%d号筷子,现在有两只筷子,开始进餐\n",i,right);
		delay(60000);
		sem_post(&chopsticks[left]);
		printf("哲学家%d放下了%d号筷子\n",i,left);
		sem_post(&m);//当哲学家放下左筷子时,信号量m+1
		sem_post(&chopsticks[right]);
		printf("哲学家%d放下了%d号筷子\n",i,right);
	}
}

int main (int argc,char **argv){
    
    
	int i;
	srand(time(NULL));
	pthread_t philo[N];
	//信号量初始化
	for(i=0;i<N;i++){
    
    
		sem_init(&chopsticks[i],0,1);
	}
	sem_init(&m,0,4);
	//创建线程
	for(i=0;i<N;i++){
    
    
		pthread_create(&philo[i],NULL,philosopher,&philosophers[i]);
	}
	//挂起线程
	for(i=0;i<N;i++){
    
    
		pthread_join(philo[i],NULL);
	}
	//销毁信号量
	for(i=0;i<N;i++){
    
    
		sem_destroy(&chopsticks[i]);
	}
	sem_destroy(&m);
}

Guess you like

Origin blog.csdn.net/ABded/article/details/106589893
Recommended