First Edition: different threads sell each other, which will lead to the final purchase of 300 tickets
Because 100 is placed in local variables, each thread has one
/* Case of using multithreading to buy tickets There are three windows, a total of 100 tickets */ #include<stdio.h> #include<pthread.h> #include<stdlib.h> void *sellticket(void*arg){ int ticket = 100; while (ticket > 0) { printf("%ld is selling the %d ticket.\n",pthread_self(),ticket); ticket--; } return NULL; } int main(void){ //Create 3 child threads pthread_t tid1,tid2,tid3; pthread_create(&tid1,NULL,sellticket,NULL); pthread_create(&tid2,NULL,sellticket,NULL); pthread_create(&tid3,NULL,sellticket,NULL); //Reclaim resources from child threads pthread_join(tid1,NULL); pthread_join(tid2,NULL); pthread_join(tid3,NULL); //Set thread separation // pthread_detach(tid1); // pthread_detach(tid2); // pthread_detach(tid3); //Exit main thread pthread_exit(NULL); return 0; }
Version 2: even if the global variable is set, the previous thread will change but the subsequent thread will not get the changed data.
Third Edition: let each thread sleep for 3000 ms, and the effect of repeatedly changing a certain data before the result is more obvious
Fourth Edition: change to sleep 6000 ms, there is a surprise, but there is a negative number!!!
/* Case of using multithreading to buy tickets There are three windows, a total of 100 tickets */ #include<stdio.h> #include<pthread.h> #include<stdlib.h> #include<unistd.h> int ticket = 100; void *sellticket(void*arg){ while (ticket > 0) { usleep(6000); printf("%ld is selling the %d ticket.\n",pthread_self(),ticket); ticket--; } return NULL; } int main(void){ //Create 3 child threads pthread_t tid1,tid2,tid3; pthread_create(&tid1,NULL,sellticket,NULL); pthread_create(&tid2,NULL,sellticket,NULL); pthread_create(&tid3,NULL,sellticket,NULL); //Reclaim resources from child threads pthread_join(tid1,NULL); pthread_join(tid2,NULL); pthread_join(tid3,NULL); //Set thread separation // pthread_detach(tid1); // pthread_detach(tid2); // pthread_detach(tid3); //Exit main thread pthread_exit(NULL); return 0; }
Why negative numbers?
When the last ticket is left, (i = = 1)
Thread 1, thread 2 and thread 3 seize the CPU together,
When thread 1 comes in, it meets the conditions (I = = 1 > 0), enters the loop, and thread 1 is forced to sleep;
Give it to thread 2. Thread 2 meets the conditions (I = = 1 > 0), enters the loop, and thread 2 is forced to sleep;
Give it to thread 3. Thread 3 meets the conditions (I = = 1 > 0), enters the loop, and thread 3 is forced to sleep;
When thread 1 wakes up, it then loops, – i, and finally i = = 0;
When thread 2 wakes up, it then loops, – i, and finally i = = -1;
When thread 3 wakes up, it then loops, – i, and finally i == -2;
Because there is no judgment when you wake up and execute it again
How to solve it?
1) When operating on variable i, other threads cannot operate on i;
2) When a thread performs a series of operations, those operations must be atomic operations. Not half of the other threads entered the loop
Plus mutex
Lock before entering the critical zone, but there will be a problem:
The final execution result is executed by the same thread.
Why does this happen?
The logic of locking in that way is: locking enters the cycle and will not be unlocked until the cycle is completed, and the tickets at the end of the cycle have been sold out.
Finally, it is changed to: the loop can be entered freely, and the data volume should be locked when it is modified.
/* Type of mutex pthread_mutex_t int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); - Initialize mutex - mutex Mutex variables that need to be initialized - attr Mutex related attributes. If NULL is passed, the default attribute is used - restrict : C The modifier of language. The modified pointer cannot be operated by another pointer pthread_mutex_t *restrict mutex = xxx; pthread_mutex_t * mutex1 = mutex; ((mutex1 cannot operate on mutex due to the restrict ion) (This operator is to limit the operation permission of the pointer enjoyed by an object.) int pthread_mutex_destroy(pthread_mutex_t *mutex); - Release mutually exclusive resources int pthread_mutex_lock(pthread_mutex_t *mutex); - Locking, blocking. If one thread locks, other threads can only block and wait int pthread_mutex_trylock(pthread_mutex_t *mutex); - Try locking. If locking fails, it will not block and will return directly int pthread_mutex_unlock(pthread_mutex_t *mutex); - Unlock */ #include<stdio.h> #include<pthread.h> #include<stdlib.h> #include<unistd.h> int ticket = 1000; //Create a mutex pthread_mutex_t mutex; // //Writing method of the first edition: in the end, there is only one thread selling tickets // void *sellticket(void*arg){ // //Lock // pthread_mutex_lock(&mutex); // //Business logic // while (ticket > 0) // { // usleep(6000); // printf("%ld is selling the %d ticket.\n",pthread_self(),ticket); // ticket--; // } // //Unlock // pthread_mutex_unlock(&mutex); // return NULL; // } //Second edition writing method void *sellticket(void*arg){ // //Lock // pthread_mutex_lock(&mutex); //Business logic while (1) { //Lock pthread_mutex_lock(&mutex); if(ticket > 0){ usleep(6000); printf("%ld is selling the %d ticket.\n",pthread_self(),ticket); ticket--; }else{ //It also needs to be unlocked here. Otherwise, if you jump out of the loop, the lock will not be released, causing the thread to fail to end //Unlock pthread_mutex_unlock(&mutex); break; } //Unlock pthread_mutex_unlock(&mutex); } return NULL; } int main(void){ //Initialize mutex pthread_mutex_init(&mutex,NULL); //Create 3 child threads pthread_t tid1,tid2,tid3; pthread_create(&tid1,NULL,sellticket,NULL); pthread_create(&tid2,NULL,sellticket,NULL); pthread_create(&tid3,NULL,sellticket,NULL); //Reclaim resources from child threads pthread_join(tid1,NULL); pthread_join(tid2,NULL); pthread_join(tid3,NULL); //Exit main thread pthread_exit(NULL); //Release mutex resources pthread_mutex_destroy(&mutex); return 0; }
The final running result: you can see the thread switching