Using the pthread_mutex_t type in Linux to implement the dining problem of philosophers, pthreadmutexlock
First of all, let's talk about what is the dining problem of philosophers, which is a classic synchronization problem in the operating system course,
The problem is as follows: for example, there are 6 philosophers and 6 chopsticks (the blue part represents the philosopher, and the purple strip part represents the chopsticks ~ Number 5! If a philosopher wants to eat, he must pick up two chopsticks on the left and right to eat at the same time! After the philosophers eat, put down the two chopsticks they picked up! In this way, other philosophers can eat with these chopsticks!
OK, so there may be a deadlock problem. For example, philosophers on The 0th took chopsticks on the 0th and philosophers on the 1st took chopsticks on the 1st! In this way, the final result is that every philosopher takes only one chopsticks, and everyone cannot eat or put down the chopsticks in his hands! In this way, a deadlock occurs!
How can we solve the deadlock? It is very simple, that is, according to the philosopher's number! If it is a philosopher with an even number, take the chopsticks on the right hand side (a small number) and the chopsticks on the left side (a big number ). The odd number philosophers are the opposite! In this way, no philosophers take only one chopsticks!
How is the specific program implemented? The Code is as follows:
1/* indicates that this program is used to simulate the dining problem of philosophers. There are 6 philosophers and 6 chopsticks 2 */3 # include <stdio. h> 4 # include <string. h> 5 # include <stdlib. h> 6 # include <unistd. h> 7 # include <errno. h> 8 # include <pthread. h> 9 10 # define B _SIZE 4096 11 # define NUM_P 6 12 13 typedef struct phi 14 {15 pthread_mutex_t chopsticks [NUM_P]; // Five chopsticks 16 int num; // philosopher's number 17 pthread_mutex_t num_lock; // philosopher's number 18} Phi, * PPhi; 19 void * tfunc (void * arg) 20 {21 P Phi sp = (PPhi) arg; 22 int phi_num; 23 int next_num; 24 25/* read the philosopher's Number */26 phi_num = sp-> num; 27 pthread_mutex_unlock (& sp-> num_lock); 28 printf ("No. % d philosopher has comed \ n ", phi_num); 29/* Next chopsticks */30 next_num = phi_num + 1> = NUM_P? Phi_num + 1-NUM_P: phi_num + 1; 31 32 sleep (5); // All threads sleep for 5 S, to wait for other threads to complete the creation. 33 34 if (phi_num % 2 = 1) // the odd number must be greater first, take a smaller 35 {36 pthread_mutex_lock (& (sp-> chopsticks [next_num]); 37 // printf ("No. % d philosopher lock the No. % d chopstick \ n ", phi_num, next_num); 38 pthread_mutex_lock (& (sp-> chopsticks [phi_num]); 39 // printf (" No. % d philosopher lock the No. % d chopstick \ n ", phi_num, phi_num); 40 41 printf (" No. % d philosophe R has eated! \ N ", phi_num); 42 43 pthread_mutex_unlock (& (sp-> chopsticks [next_num]); 44 // printf (" No. % d philosopher unlock the No. % d chopstick \ n ", phi_num, next_num); 45 pthread_mutex_unlock (& (sp-> chopsticks [phi_num]); 46 // printf (" No. % d philosopher unlock the No. % d chopstick \ n ", phi_num, phi_num); 47} 48 else // take the even number first, take the 49 {50 pthread_mutex_lock (& (sp-> chopsticks [phi_num]); 51 // printf ("No. % d philosopher loc K the No. % d chopstick \ n ", phi_num, phi_num); 52 pthread_mutex_lock (& (sp-> chopsticks [next_num]); 53 // printf (" No. % d philosopher lock the No. % d chopstick \ n ", phi_num, next_num); 54 55 printf (" No. % d philosopher has eated! \ N ", phi_num); 56 57 pthread_mutex_unlock (& (sp-> chopsticks [phi_num]); 58 // printf (" No. % d philosopher unlock the No. % d chopstick \ n ", phi_num, phi_num); 59 pthread_mutex_unlock (& (sp-> chopsticks [next_num]); 60 // printf (" No. % d philosopher unlock the No. % d chopstick \ n ", phi_num, next_num); 61} 62 63 return (void *) 0; 64} 65 int main (int argc, char * argv []) 66 {67 int err; 68 pthread_t tid [NUM_P]; 69 char Buf_err [B _SIZE]; // used to save the error message 70 void * retv; // the return value of the subthread 71 Phi phis; 72 73 for (int loop = 0; loop <NUM_P; loop ++) 74 {75/* set the philosopher's Number */76 pthread_mutex_lock (& phis. num_lock); 77 phis. num = loop; 78 79/* Create Sub-threads as philosophers */80 err = pthread_create (& tid [loop], NULL, tfunc, & phis); 81 if (0! = Err) 82 {83 memset (buf_err, 0, B _SIZE); 84 sprintf (buf_err, "[create]: % s \ n", strerror (err )); 85 fputs (buf_err, stderr); 86 exit (EXIT_FAILURE); 87} 88} 89 90 for (int loop = 0; loop <NUM_P; loop ++) 91 {92 err = pthread_join (tid [loop], & retv); 93 if (0! = Err) 94 {95 memset (buf_err, 0, B _SIZE); 96 sprintf (buf_err, "[join]: % s \ n", strerror (err )); 97 fputs (buf_err, stderr); 98 exit (EXIT_FAILURE); 99} 100 101 printf ("Main: thread return the value: % d \ n", (int) retv ); 102} 103 104 return 0; 105}
In the above program, I created a struct PHI! Among them, chopsticks is the five mutex locks defined to represent Five chopsticks! The num variable is used to represent the philosopher's number, and the num_lock variable is used to lock the philosopher's number. Why is this setting necessary!
The main program is to create a NUM_P subthread to represent so many philosophers! In the child thread, you need to choose different methods to take chopsticks Based on the parity of the philosopher's number! This requires a philosopher ID to be assigned to this subthread! What is it passed through? It is the num variable in the PHI struct! Here we will encounter a problem! If num is set in the main thread, then a sub-thread is created, but the sub-thread has not had time to read the value of this num, and the main thread has started the next loop, so it is very likely that the num value read by the subthread is not what we want it to read! So the num_lock lock is used here. After the main thread writes the num value, it locks the num_lock and then the sub-thread reads the num, to unlock the num_lock lock, and then the main thread can carry out the next loop! This ensures that the number read by the sub-thread is the number we want to pass to him!
In the child thread, I first output "No. % d philosopher has comed \ n", indicating that a child thread has been created! Then let the thread sleep for 5 S and wait for other sub-threads to be created. (This is not required, but I feel like it makes philosophers start eating together... ^ _~)! Then, according to the above idea, philosophers of even numbers should first take chopsticks on the right hand side and then chopsticks on the left side. philosophers of odd numbers are exactly the opposite! This will avoid deadlocks!
Another problem is that I defined the next_num variable in the Child thread, which is used to represent the value of the next chopsticks obtained by philosophers, because the next chopsticks of the philosopher with the largest number is chopsticks No. 0th, I used an if clause to tell the difference!
The running result of the program is as follows:
OK. That's all! Hope to help those who are learning the operating system!