Foreword
Then, the blogger here will first check out some columns full of dry goods!
This contains a lot of data structure learning summaries of bloggers, Each article is written with super heart, and interested partners should support it!
Hand tear data structure https:// blog.csdn.net/yu_cblog/category_11490888.html?spm=1001.2014.3001.5482https://blog.csdn.net/yu_cblog/category_11490888.html?spm=1001.2014. 3001.5482
Here is the STL source code analysis column, which will continue to update the simulation implementation of various STL containers.
Algorithm column https://blog.csdn.net /yu_cblog/category_11464817.htmlhttps://blog.csdn.net/yu_cblog/category_11464817.html
STL source code Analysis https://blog.csdn.net/yu_cblog/category_11983210.html?spm=1001.2014.3001.5482https://blog.csdn.net/yu_cblog/category_11983210.html ?spm=1001.2014.3001.5482
Why mutexes are needed
In order to explain clearly why the lock is needed, the blogger shows you through a piece of code.
This is a piece of code for multi-thread ticket grabbing logic:
There are a total of tickets tickets, we create three threads to grab tickets
According to the principle: when the tickets are sold out, the number of votes should be 0
#include <iostream> #include <pthread.h> #include <unistd.h> #include <cstdio> #include <vector> // If multiple threads access the same global variable and perform data calculations on it, will multiple threads affect each other? int tickets = 10000; // 10000 here is the critical resource void *getTickets(void *args) { (void) args; while (true) { if (tickets > 0) { usleep(1000); printf("%p: %d\\ ", pthread_self(), tickets); tickets--; } else { // no more tickets break; } } } int main() { pthread_t t1, t2, t3; // The logic of multi-thread grabbing tickets pthread_create( & amp;t1, nullptr, getTickets, nullptr);//Create thread pthread_create( &t2, nullptr, getTickets, nullptr); pthread_create( &t3, nullptr, getTickets, nullptr); pthread_join(t1, nullptr);//Thread waiting pthread_join(t2, nullptr); pthread_join(t3, nullptr); return 0; }
Phenomena
In the end, I got -1, which is unreasonable!
In fact, a sentence in the code actually corresponds to more than one sentence in assembly language. The thread may be switched by the scheduler at any time. At this time, for the data in the unprotected memory, the problem of data inconsistency may occur.
Here, the blogger will give you an example, and everyone will understand.
Assuming that the tickets are now 10000, thread A is now ready to perform the subtraction operation.
The subtraction operation corresponds to three steps:
- Load tickets to cpu
- cpu for calculation
- Rewrite tickets back to memory
Assume that thread A has completed the first two steps, and when it is ready to perform the third step, thread A is cut off. At this time, thread A will store the number 9999 in the register, and when A is switched back next time, it will Continue to the third part: the operation of putting the data back into memory. However, because the memory of tickets is not protected, before thread A is switched back, the scheduler may have reduced the number of tickets to 5000. At this time, if thread A is switched back again, the tickets will be changed back to 9999 . This is the data inconsistency problem caused by parallel computing!
So we need to protect the memory of tickets! Since the thread is cut off, it is completely determined by the scheduler, so we have no way to control it. The only thing we can do is that when the thread is cut off, other threads cannot access tickets and must wait. After A is processed, other threads can process it!
In the operating system, tickets, which can be accessed and modified by multiple execution streams at the same time, are called critical resources.
Mutex
Why is the lock not added before the while, and the unlock is placed after the end of the while?
If this is the case, the logic of the entire ticket grabbing is completely serialized. What is the difference between this and no multi-threading? So when we lock, we must ensure the granularity of the lock, the smaller the better!
#include <iostream> #include <pthread.h> #include <unistd.h> #include <cstdio> #include <vector> #include <time.h> // To protect it with a lock // pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; // pthread_mutex_t is a data type provided by the native thread library int tickets = 10000; #define THREAD_NUM 5 // Define the number of threads struct ThreadData { public: ThreadData(const std::string n, pthread_mutex_t *pm) : tname(n), pmtx(pm) {} public: std::string tname; pthread_mutex_t *pmtx; }; void *getTickets(void *args) { ThreadData *td = (ThreadData *)args; while (true) { pthread_mutex_lock(td->pmtx); if (tickets > 0) // The essence of judgment is also a kind of calculation { usleep(rand() % 1500 + 200); // Let the sleep time be random printf("%p: %d\\ ", pthread_self(), tickets); tickets--; pthread_mutex_unlock(td->pmtx); } else { // no more tickets pthread_mutex_unlock(td->pmtx); break; } } delete td; } int main() { pthread_mutex_t mtx; pthread_mutex_init( &mtx, nullptr); srand((unsigned long)time(nullptr) ^ getpid() ^ 0x147); pthread_t t[THREAD_NUM]; // The logic of multi-thread grabbing tickets for (int i = 0; i < 5; i ++ ) { std::string name = "thread"; name + = std::to_string(i + 1); ThreadData *td = new ThreadData(name, &mtx); pthread_create(t + i, nullptr, getTickets, (void *)td); } for (int i = 0; i <thREAD_NUM; i ++ ) { pthread_join(t[i], nullptr); } pthread_mutex_destroy( &mtx); return 0; }
After the lock is added, will the thread switch in the critical section?
Will it switch, will there be a problem? No!
Although it is switched, we are holding the lock to be switched!
Other execution flows want to execute this part of the code and apply for locks, so other execution flows will fail to apply for locks
Does locking mean serial execution?
Yes! Execution of critical section code must be serial
To access critical resources, each thread must apply for a lock. The premise is that each thread must first see the same lock & amp; & amp; to access it. Then, is the lock itself a shared critical resource? ? Who will guarantee the safety of the lock? So in order to ensure the safety of the lock, the application and release of the lock must be atomic!!!
How is it guaranteed? What exactly is a lock? How is a lock implemented?
The principle of lock
End
Seeing this, everyone should have a preliminary understanding of locks. However, this blog is just to let everyone see what a lock is. In real applications, locks are not used in this way. There is still a lot of complicated and in-depth knowledge about mutexes in Linux. As for Linux multi-threading, the most important thing I think is the "producer-consumer model". This is really important. In the next few blogs, bloggers will talk about this content! If you think these contents are helpful to you, don't forget to like, collect and forward!
The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. CS introductory skill tree Introduction to LinuxFirst-knowledge of Linux28810 People are studying systematically